From b798385bdb1148852361f5ad794f853e2425d0d5 Mon Sep 17 00:00:00 2001 From: Gabriele Oliaro Date: Fri, 15 Nov 2024 12:17:26 -0500 Subject: [PATCH 1/5] Specscheduler evaluation support code (#1541) --- .gitignore | 3 + CMakeLists.txt | 1 + benchmarking/average_accepted_tokens.pdf | Bin 0 -> 15738 bytes benchmarking/benchmark_incr_dec.sh | 88 ++ benchmarking/benchmark_specinfer.sh | 109 +++ benchmarking/get_sharegpt_trace.py | 206 +++++ benchmarking/get_wildchat_trace.py | 64 ++ benchmarking/plot_results.ipynb | 776 ++++++++++++++++++ .../queueing_time_vs_arrival_rate.pdf | Bin 0 -> 18042 bytes benchmarking/throughput_vs_tpot.pdf | Bin 0 -> 28243 bytes benchmarking/ttft_vs_arrival_rate.pdf | Bin 0 -> 16898 bytes include/flexflow/batch_config.h | 1 + include/flexflow/config.h | 1 + include/flexflow/inference.h | 1 + include/flexflow/model.h | 4 +- .../ops/spec_inc_multihead_self_attention.h | 2 + ...spec_inc_multihead_self_attention_params.h | 3 +- include/flexflow/optimizer.h | 8 +- .../parallel_ops/kernels/allreduce_kernels.h | 8 +- include/flexflow/request_manager.h | 88 +- include/flexflow/utils/communication_buffer.h | 5 +- include/flexflow/utils/file_loader.h | 52 +- include/flexflow/utils/memory_allocator.h | 5 +- inference/incr_decoding/incr_decoding.cc | 23 +- inference/simplified_infer/CMakeLists.txt | 74 ++ inference/simplified_infer/incr_dec.cc | 473 +++++++++++ inference/simplified_infer/specinfer.cc | 692 ++++++++++++++++ inference/spec_infer/spec_infer.cc | 48 +- inference/trace_generator/trace_generator.cc | 48 +- inference/utils/mem_analysis.py | 115 +++ python/flexflow/core/__init__.py | 1 + python/flexflow/serve/models/llama.py | 4 + python/flexflow/serve/serve.py | 4 +- src/c/flexflow_c.cc | 3 +- src/mapper/mapper.cc | 37 +- src/ops/add_bias_residual_layer_norm.cpp | 3 +- src/ops/add_bias_residual_layer_norm.cu | 3 +- src/ops/arg_topk.cu | 4 +- src/ops/argmax.cpp | 3 +- src/ops/argmax.cu | 6 +- src/ops/fused.cc | 4 +- src/ops/fused.cpp | 2 +- src/ops/gumbel_topk.cu | 2 +- src/ops/inc_multihead_self_attention.cpp | 6 +- src/ops/inc_multihead_self_attention.cu | 6 +- src/ops/kernels/linear_kernels.cu | 2 +- src/ops/kernels/residual_rms_norm_kernels.cpp | 3 +- src/ops/kernels/residual_rms_norm_kernels.cu | 3 +- src/ops/kernels/rms_norm_kernels.cpp | 3 +- src/ops/kernels/rms_norm_kernels.cu | 3 +- src/ops/layer_norm.cu | 3 +- src/ops/residual_layer_norm.cpp | 3 +- src/ops/residual_layer_norm.cu | 3 +- src/ops/sampling.cpp | 6 +- src/ops/sampling.cu | 6 +- src/ops/spec_inc_multihead_self_attention.cc | 23 +- src/ops/spec_inc_multihead_self_attention.cpp | 6 +- src/ops/tree_inc_multihead_self_attention.cpp | 6 +- src/parallel_ops/allreduce.cc | 6 +- .../kernels/allreduce_kernels.cpp | 12 +- src/parallel_ops/kernels/allreduce_kernels.cu | 129 +-- src/runtime/batch_config.cc | 42 + src/runtime/file_loader.cc | 217 ++--- src/runtime/graph.cc | 36 +- src/runtime/inference_manager.cc | 72 +- src/runtime/memory_allocator.cc | 31 +- src/runtime/model.cc | 49 +- src/runtime/optimizer_kernel.cpp | 12 +- src/runtime/optimizer_kernel.cu | 8 +- src/runtime/parallel_tensor.cc | 60 +- src/runtime/request_manager.cc | 326 ++++++-- src/utils/communication_buffer.cu | 22 +- tests/inference/huggingface_inference.py | 2 +- 73 files changed, 3585 insertions(+), 495 deletions(-) create mode 100644 benchmarking/average_accepted_tokens.pdf create mode 100755 benchmarking/benchmark_incr_dec.sh create mode 100755 benchmarking/benchmark_specinfer.sh create mode 100644 benchmarking/get_sharegpt_trace.py create mode 100644 benchmarking/get_wildchat_trace.py create mode 100644 benchmarking/plot_results.ipynb create mode 100644 benchmarking/queueing_time_vs_arrival_rate.pdf create mode 100644 benchmarking/throughput_vs_tpot.pdf create mode 100644 benchmarking/ttft_vs_arrival_rate.pdf create mode 100644 inference/simplified_infer/CMakeLists.txt create mode 100644 inference/simplified_infer/incr_dec.cc create mode 100644 inference/simplified_infer/specinfer.cc create mode 100644 inference/utils/mem_analysis.py diff --git a/.gitignore b/.gitignore index f21d30b2a7..d7917b34dd 100644 --- a/.gitignore +++ b/.gitignore @@ -192,3 +192,6 @@ inference_tensors tests/inference/python_test_configs/*.json core.* +*.out +sharegpt.json +wildchat.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 577a2215db..978d84de4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -580,6 +580,7 @@ if(NOT BUILD_LEGION_ONLY) if(FF_BUILD_ALL_INFERENCE_EXAMPLES OR FF_BUILD_ALL_EXAMPLES) add_subdirectory(inference/spec_infer) + add_subdirectory(inference/simplified_infer) add_subdirectory(inference/incr_decoding) add_subdirectory(inference/trace_generator) endif() diff --git a/benchmarking/average_accepted_tokens.pdf b/benchmarking/average_accepted_tokens.pdf new file mode 100644 index 0000000000000000000000000000000000000000..896519d5d47abe1cf317cf20a46c0599432e6e0f GIT binary patch literal 15738 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 A761SM literal 0 HcmV?d00001 diff --git a/benchmarking/benchmark_incr_dec.sh b/benchmarking/benchmark_incr_dec.sh new file mode 100755 index 0000000000..3ddcb2271a --- /dev/null +++ b/benchmarking/benchmark_incr_dec.sh @@ -0,0 +1,88 @@ +#! /usr/bin/env bash +set -x +set -e + +# Cd into directory holding this script +cd "${BASH_SOURCE[0]%/*}/../build" + +# export BUILD_TYPE=Debug +# ../config/config.linux +make -j install + +model_name=meta-llama/Llama-3.1-70B-Instruct +NGPUS=8 +NCPUS=16 +FSIZE=36000 +ZSIZE=200000 +CSIZE=100000 + +# comment these lines in for debugging +# model_name=meta-llama/Llama-3.1-8B-Instruct +# NGPUS=8 +# FSIZE=36000 +# ZSIZE=30000 +# CSIZE=100000 + + + +MAX_SEQ_LEN=7000 +tokens_per_batch=1024 + +batch_sizes=( + 8 + 4 +) + +request_per_second_values=( + -1 + 1 + 2 + 4 + 8 +) + +dataset_name="sharegpt" +dataset_fp="../wildchat/${dataset_name}.json" +partition_name="all" + +export LEGION_BACKTRACE=1 + +# python -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='meta-llama/Llama-3.1-70B-Instruct', allow_patterns='*.safetensors', max_workers=30)" +# python ../inference/utils/download_hf_model.py --half-precision-only $model_name --refresh-cache + +for k in "${!request_per_second_values[@]}"; do +for j in "${!batch_sizes[@]}"; do + batch_size=${batch_sizes[$j]} + request_per_second=${request_per_second_values[$k]} + + echo "Running dataset ${dataset_fp} with model ${model_name}, batch size ${batch_size}, tokens per batch ${tokens_per_batch}, and request per second ${request_per_second}" + # create model name version where "/" is replaced with "-" + model_name_=$(echo $model_name | tr / -) + if [ $request_per_second -gt 0 ]; then + rate=$request_per_second + else + rate="offline" + fi + log_fp="/usr/FlexFlow/inference/output/incr_dec_llm_${model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.log" + output_fp="/usr/FlexFlow/inference/output/incr_dec_llm_${model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.json" + metrics_fp="/usr/FlexFlow/inference/output/incr_dec_llm_${model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.csv" + rm $metrics_fp $output_fp $log_fp || true + + time ./inference/suffix_decoding/incr_dec \ + -ll:gpu $NGPUS -ll:cpu $NCPUS -ll:util $NCPUS \ + -tensor-parallelism-degree $NGPUS \ + -ll:fsize $FSIZE -ll:zsize $ZSIZE -ll:csize $CSIZE \ + --fusion \ + --max-sequence-length $MAX_SEQ_LEN \ + --max-requests-per-batch $batch_size \ + --max-tokens-per-batch $tokens_per_batch \ + --max-output-length 1024 \ + --request-per-second ${request_per_second} \ + -llm-model $model_name \ + -trace ${dataset_fp} \ + -trace-output-path ${output_fp} \ + -csv-output-path $metrics_fp \ + -target-partition ${partition_name} \ + 2>&1 | tee ${log_fp} +done +done \ No newline at end of file diff --git a/benchmarking/benchmark_specinfer.sh b/benchmarking/benchmark_specinfer.sh new file mode 100755 index 0000000000..5fe881f08d --- /dev/null +++ b/benchmarking/benchmark_specinfer.sh @@ -0,0 +1,109 @@ +#! /usr/bin/env bash +set -x +set -e + +# Cd into directory holding this script +cd "${BASH_SOURCE[0]%/*}/../build" + +# export BUILD_TYPE=Debug +# ../config/config.linux +make -j +source ./set_python_envs.sh +# reset + +model_name=meta-llama/Llama-3.1-70B-Instruct +NGPUS=8 +NCPUS=16 +FSIZE=36000 +ZSIZE=200000 +CSIZE=100000 + +# comment these lines in for debugging +# model_name=meta-llama/Llama-3.1-8B-Instruct +# NGPUS=8 +# FSIZE=36000 +# ZSIZE=30000 +# CSIZE=100000 +###################################### + +small_model_names=( + Zhuominc/Llama-3-330M + meta-llama/Llama-3.2-1B-Instruct + meta-llama/Llama-3.2-3B-Instruct + meta-llama/Llama-3.1-8B-Instruct +) + +MAX_SEQ_LEN=7000 +tokens_per_batch=1024 +max_tree_depth=8 +expansion_degree=3 + +batch_sizes=( + 8 + 4 +) + +request_per_second_values=( + -1 + 1 + 2 + 4 + 8 +) + +dataset_name="sharegpt" +dataset_fp="../wildchat/${dataset_name}.json" +partition_name="all" + +export LEGION_BACKTRACE=1 + +# python -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='meta-llama/Llama-3.1-70B-Instruct', allow_patterns='*.safetensors', max_workers=30)" +python ../inference/utils/download_hf_model.py --half-precision-only $model_name +for small_model_name in "${small_model_names[@]}"; do + python ../inference/utils/download_hf_model.py --half-precision-only $small_model_name +done + +for k in "${!request_per_second_values[@]}"; do +for j in "${!batch_sizes[@]}"; do +for i in "${!small_model_names[@]}"; do + small_model_name=${small_model_names[$i]} + batch_size=${batch_sizes[$j]} + request_per_second=${request_per_second_values[$k]} + + echo "Running dataset ${dataset_fp} with model ${model_name}, draft model ${small_model_name}, batch size ${batch_size}, tokens per batch ${tokens_per_batch}, and request per second ${request_per_second}" + # create model name version where "/" is replaced with "-" + model_name_=$(echo $model_name | tr / -) + small_model_name_=$(echo $small_model_name | tr / -) + if [ $request_per_second -gt 0 ]; then + rate=$request_per_second + else + rate="offline" + fi + log_fp="/usr/FlexFlow/inference/output/specinfer_llm_${model_name_}_ssm_${small_model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.log" + output_fp="/usr/FlexFlow/inference/output/specinfer_llm_${model_name_}_ssm_${small_model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.json" + metrics_fp="/usr/FlexFlow/inference/output/specinfer_llm_${model_name_}_ssm_${small_model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.csv" + rm $metrics_fp $output_fp $log_fp || true + + time ./inference/suffix_decoding/specinfer \ + -ll:gpu $NGPUS -ll:cpu $NCPUS -ll:util $NCPUS \ + -tensor-parallelism-degree $NGPUS \ + -ssm-tp-degree $NGPUS \ + -ll:fsize $FSIZE -ll:zsize $ZSIZE -ll:csize $CSIZE \ + --fusion \ + --max-sequence-length $MAX_SEQ_LEN \ + --max-requests-per-batch $batch_size \ + --max-tokens-per-batch $tokens_per_batch \ + --max-output-length 1024 \ + --max-tree-depth ${max_tree_depth} \ + --expansion-degree ${expansion_degree} \ + --request-per-second ${request_per_second} \ + -llm-model $model_name \ + -ssm-model $small_model_name \ + -trace ${dataset_fp} \ + -trace-output-path ${output_fp} \ + -csv-output-path $metrics_fp \ + -target-partition ${partition_name} \ + 2>&1 | tee ${log_fp} +done +done +done \ No newline at end of file diff --git a/benchmarking/get_sharegpt_trace.py b/benchmarking/get_sharegpt_trace.py new file mode 100644 index 0000000000..dbe8f4d3bc --- /dev/null +++ b/benchmarking/get_sharegpt_trace.py @@ -0,0 +1,206 @@ +from dataclasses import asdict, dataclass, field +import json +import os +import random +import requests +from tqdm.asyncio import tqdm +from typing import List, Optional +from collections import OrderedDict +from transformers import AutoTokenizer + +SHAREGPT_URL = "https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json" + +@dataclass +class TraceEntry: + prompt: str + response: str + prompt_length: int + response_length: int + +@dataclass +class TracePartition: + partition_name: str + model_name: str + num_warmup_requests: int + training_entries: List[TraceEntry] + eval_entries: List[TraceEntry] + +@dataclass +class TraceMetadata: + avg_entries_per_partition: float + max_prompt_length: int + min_prompt_length: int + avg_prompt_length: float + max_response_length: int + min_response_length: int + avg_response_length: float + max_total_length: int + +@dataclass +class Trace: + partitions: List[TracePartition] + metadata: TraceMetadata = field(default_factory=lambda: TraceMetadata(0, 0, 0, 0, 0, 0, 0,0)) + +def download_and_cache_file(url: str, filename: Optional[str] = None): + """Read and cache a file from a url.""" + if filename is None: + filename = os.path.join("/tmp", url.split("/")[-1]) + + # Check if the cache file already exists + if os.path.exists(filename): + return filename + + print(f"Downloading from {url} to {filename}") + + # Stream the response to show the progress bar + response = requests.get(url, stream=True) + response.raise_for_status() # Check for request errors + + # Total size of the file in bytes + total_size = int(response.headers.get("content-length", 0)) + chunk_size = 1024 # Download in chunks of 1KB + + # Use tqdm to display the progress bar + with open(filename, "wb") as f, tqdm( + desc=filename, + total=total_size, + unit="B", + unit_scale=True, + unit_divisor=1024, + ) as bar: + for chunk in response.iter_content(chunk_size=chunk_size): + f.write(chunk) + bar.update(len(chunk)) + + return filename + +def get_warmup_entries(model_name: str, num_warmup_requests: int) -> List[TraceEntry]: + """ + Get a list of warmup entries for a model. + + Args: + model_name (str): The name of the model. + num_warmup_requests (int): The number of warmup requests to generate. + + Returns: + List[TraceEntry]: A list of warmup entries. + """ + warmup_entries = [] + tokenizer = AutoTokenizer.from_pretrained(model_name) + for i in range(num_warmup_requests): + prompt = "Hello, how are you?" + prompt = tokenizer.apply_chat_template( + [{"role": "user", "content": prompt}], + add_generation_prompt=True, + tokenize=False, + ) + response = "I'm doing well, thank you for asking." + prompt_length = len(tokenizer(prompt)["input_ids"]) + response_length = len(tokenizer(response)["input_ids"]) + warmup_entries.append(TraceEntry(prompt, response, prompt_length, response_length)) + return warmup_entries + +def build_trace(model_name: str, num_entries: int, num_warmup_requests: int, seed: int): + # Download sharegpt if necessary + dataset_path = download_and_cache_file(SHAREGPT_URL) + + # Load the dataset. + with open(dataset_path) as f: + dataset = json.load(f, object_pairs_hook=OrderedDict) + # Filter out the conversations with less than 2 turns. + dataset = [data for data in dataset if len(data["conversations"]) >= 2] + # Only keep the first two turns of each conversation. + dataset = [ + (data["conversations"][0]["value"], data["conversations"][1]["value"]) + for data in dataset + if data["conversations"][0]["from"] == "human" and data["conversations"][1]["from"] == "gpt" + ] + + # Shuffle the dataset. + random.seed(seed) + random.shuffle(dataset) + + tokenizer = AutoTokenizer.from_pretrained(model_name) + + trace = Trace(partitions=[]) + partition = TracePartition( + partition_name="all", + model_name=model_name, + num_warmup_requests=num_warmup_requests, + training_entries=[], + eval_entries=[], + ) + trace_metadata = TraceMetadata( + avg_entries_per_partition=0, + max_prompt_length=0, + min_prompt_length=float("inf"), + avg_prompt_length=0, + max_response_length=0, + min_response_length=float("inf"), + avg_response_length=0, + max_total_length=0, + ) + + partition.eval_entries += get_warmup_entries(model_name, num_warmup_requests) + + for i in tqdm(range(len(dataset))): + if len(partition.eval_entries) == num_entries: + break + + # Tokenize the prompts and completions. + prompt = dataset[i][0] + prompt = tokenizer.apply_chat_template( + [{"role": "user", "content": prompt}], + add_generation_prompt=True, + tokenize=False, + ) + response = dataset[i][1] + prompt_length = len(tokenizer(prompt)["input_ids"]) + response_length = len(tokenizer(response)["input_ids"]) + new_entry = TraceEntry(prompt, response, prompt_length, response_length) + partition.eval_entries.append(new_entry) + trace_metadata.max_prompt_length = max(trace_metadata.max_prompt_length, prompt_length) + trace_metadata.min_prompt_length = min(trace_metadata.min_prompt_length, prompt_length) + trace_metadata.avg_prompt_length += prompt_length + trace_metadata.max_response_length = max(trace_metadata.max_response_length, response_length) + trace_metadata.min_response_length = min(trace_metadata.min_response_length, response_length) + trace_metadata.avg_response_length += response_length + trace_metadata.max_total_length = max(trace_metadata.max_total_length, prompt_length + response_length) + trace_metadata.avg_prompt_length /= len(partition.eval_entries) + trace_metadata.avg_response_length /= len(partition.eval_entries) + trace_metadata.avg_entries_per_partition = len(partition.eval_entries) + + trace.partitions.append(partition) + trace.metadata = trace_metadata + + return trace + +def save_trace(trace: Trace, output_path: str): + """ + Save a Trace instance to a JSON file. + + Args: + trace (Trace): The trace to save. + output_path (str): The path where the JSON file will be saved. + """ + # Convert the Trace instance to a dictionary + trace_dict = asdict(trace) + + # Save the dictionary as a JSON file + with open(output_path, 'w') as f: + json.dump(trace_dict, f, indent=2) + + print(f"Trace saved to {output_path}") + +if __name__ == "__main__": + # Change directory to that holding this script + os.chdir(os.path.dirname(os.path.abspath(__file__))) + + num_entries=125 + num_warmup_requests=8 + seed=42 + + trace = build_trace("meta-llama/Llama-3.1-70B-Instruct", num_entries, num_warmup_requests, seed) + print(trace.metadata) + # Save prompts list to a json file + save_trace(trace, "sharegpt.json") \ No newline at end of file diff --git a/benchmarking/get_wildchat_trace.py b/benchmarking/get_wildchat_trace.py new file mode 100644 index 0000000000..53ee46efb2 --- /dev/null +++ b/benchmarking/get_wildchat_trace.py @@ -0,0 +1,64 @@ +import datasets +from transformers import AutoTokenizer +from tqdm import tqdm +import json, os + +def build_trace(dataset: datasets.Dataset, model_name: str, num_entries: int, seed: int): + tokenizer = AutoTokenizer.from_pretrained(model_name) + + dataset = dataset["train"].filter( + lambda x: x["model"] == "gpt-4" and x["turn"] == 1 and x["language"] == "English" + ).shuffle(seed=seed).select(range(num_entries)) + pairs = [] + for row in dataset: + assert len(row["conversation"]) == 2 + assert row["conversation"][0]["role"] == "user" + assert row["conversation"][1]["role"] == "assistant" + pairs.append(( + row["conversation"][0]["content"], + row["conversation"][1]["content"], + )) + + prompts = [] + avg_prompt_length = 0 + min_prompt_length = float("inf") + max_prompt_length = 0 + avg_response_length = 0 + min_response_length = float("inf") + max_response_length = 0 + max_total_length = 0 + for prompt, response in tqdm(pairs, desc="Processing HF trace"): + prompt = tokenizer.apply_chat_template( + [{"role": "user", "content": prompt}], + add_generation_prompt=True, + tokenize=False, + ) + prompt_length = len(tokenizer(prompt)["input_ids"]) + response_length = len(tokenizer(response)["input_ids"]) + prompts.append(prompt) + avg_prompt_length += prompt_length + avg_response_length += response_length + min_prompt_length = min(min_prompt_length, prompt_length) + min_response_length = min(min_response_length, response_length) + max_prompt_length = max(max_prompt_length, prompt_length) + max_response_length = max(max_response_length, response_length) + max_total_length = max(max_total_length, prompt_length + response_length) + avg_prompt_length /= len(prompts) + avg_response_length /= len(prompts) + + return prompts, max_prompt_length, max_response_length, avg_prompt_length, avg_response_length, min_prompt_length, min_response_length, max_total_length + +if __name__ == "__main__": + # Change directory to that holding this script + os.chdir(os.path.dirname(os.path.abspath(__file__))) + + dataset = datasets.load_dataset("allenai/WildChat") + prompts, max_prompt_length, max_response_length, avg_prompt_length, avg_response_length, min_prompt_length, min_response_length, max_total_length = build_trace(dataset, "meta-llama/Llama-3.1-70B-Instruct", 250, 42) + print(f"Number of prompts: {len(prompts)}") + print(f"Prompt lengths: [{min_prompt_length} -> {max_prompt_length}] (avg: {avg_prompt_length})") + print(f"Response lengths: [{min_response_length} -> {max_response_length}] (avg: {avg_response_length})") + print(f"Max total length: {max_total_length}") + # Save prompts list to a json file + + with open("wildchat.json", "w") as f: + json.dump(prompts, f, indent=2) \ No newline at end of file diff --git a/benchmarking/plot_results.ipynb b/benchmarking/plot_results.ipynb new file mode 100644 index 0000000000..39047b86ce --- /dev/null +++ b/benchmarking/plot_results.ipynb @@ -0,0 +1,776 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/usr/FlexFlow/inference/output\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import os\n", + "os.chdir(\"/usr/FlexFlow/inference/output\")\n", + "print(os.getcwd())" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "small_model_names = [\n", + " \"Zhuominc/Llama-3-330M\",\n", + " \"meta-llama/Llama-3.2-1B-Instruct\",\n", + " # \"meta-llama/Llama-3.2-3B-Instruct\",\n", + " \"meta-llama/Llama-3.1-8B-Instruct\",\n", + "]\n", + "batch_sizes=[4,8]\n", + "arrival_rates=[\"offline\", \"1\", \"2\", \"4\", \"8\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def get_speculation_len(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1 or request_step_idx is < 0\n", + " df = df[(df[\"is_warmup_request\"] == 0) & (df[\"request_step_idx\"] >= 0)]\n", + " return df[\"num_speculated_tokens\"].mean()\n", + "\n", + "def get_accepted_len(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1 or request_step_idx is < 0\n", + " df = df[(df[\"is_warmup_request\"] == 0) & (df[\"request_step_idx\"] >= 0)]\n", + " return df[\"num_accepted_tokens\"].mean()\n", + "\n", + "def get_acceptance_rates(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1 or request_step_idx is < 0\n", + " df = df[(df[\"is_warmup_request\"] == 0) & (df[\"request_step_idx\"] >= 0)]\n", + " # group = df.groupby(\"request_guid\", as_index=False)\n", + " num_speculated_tokens = df[\"num_speculated_tokens\"].sum()\n", + " num_accepted_tokens = df[\"num_accepted_tokens\"].sum()\n", + " return num_accepted_tokens/num_speculated_tokens\n", + "\n", + "def get_tpot(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1 or request_step_idx is < 0\n", + " df = df[(df[\"is_warmup_request\"] == 0) & (df[\"request_step_idx\"] >= 0)]\n", + " group = df.groupby(\"request_guid\", as_index=False)\n", + " min_time = group[\"timestamp\"].min()[\"timestamp\"]\n", + " max_time = group[\"timestamp\"].max()[\"timestamp\"]\n", + " num_tokens = group[\"num_generated_tokens\"].sum()[\"num_generated_tokens\"]\n", + " tpots = (max_time - min_time) / num_tokens / 1000\n", + " return tpots.mean()\n", + "\n", + "def get_throughput(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1 or request_step_idx is < 0\n", + " df = df[(df[\"is_warmup_request\"] == 0) & (df[\"request_step_idx\"] >= 0)]\n", + " num_tokens = df[\"num_generated_tokens\"].sum()\n", + " total_time = df[\"timestamp\"].max() - df[\"timestamp\"].min() # in microseconds\n", + " total_time = total_time / 1000000 # convert to seconds\n", + " throughput = num_tokens / total_time # (tokens/sec)\n", + " return throughput\n", + "\n", + "def get_ttft(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1\n", + " df = df[(df[\"is_warmup_request\"] == 0)]\n", + " group = df.groupby(\"request_guid\", as_index=False)\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + " # convert to milliseconds from microseconds\n", + " return ttft.mean()[1] / 1000\n", + "\n", + "def get_queueing_time(filepath):\n", + " df = pd.read_csv(filepath)\n", + " # remove entries where is_warmup_request is 1\n", + " df = df[(df[\"is_warmup_request\"] == 0)]\n", + " group = df.groupby(\"request_guid\", as_index=False)\n", + " # in each group, find the difference between the timestampt at request_step_idx=-1 and the timestamp at request_step_idx=-2.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + " # convert to seconds from microseconds\n", + " return queueing_time.mean()[1] / 1000000\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9wAAAPECAYAAABc1TPrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAACsUklEQVR4nOzdeXxM1//H8fdkMUlI7EEIiVC72rWU2PdYqlVULW1RS7X17V6K0qKtLqpFUZRYaqmuqrSxdaHW6rf2SilaSxGEiMz5/eGX+ZpOkIm5YvT1fDzyYM49c+9n7owb7zn3nmszxhgBAAAAAACv8svuAgAAAAAAuBURuAEAAAAAsACBGwAAAAAACxC4AQAAAACwAIEbAAAAAAALELgBAAAAALAAgRsAAAAAAAsQuAEAAAAAsACBGwAAAAAACxC4AQC3hAYNGqhixYrZXUamzZo1S2XLllVgYKDy5MmT3eX4tAYNGqhBgwY3ZFvDhw+XzWbTsWPHbsj2AAC+jcANAP/w3nvvyWazqXbt2tldyk0nKipKNptNjz76qNuylStXymazaeHChdlQmW/ZsWOHevbsqZiYGE2ZMkXvv/9+pp739NNPy2az6b777rO4Qu/7/vvvNXz4cJ08efKGbzs9JF/r50aF9n+jzz77TLGxsQoPD1dISIhKliypTp066auvvnL2OXTokIYPH64tW7ZkX6EA4GUB2V0AANxs4uPjFRUVpfXr12vPnj0qVapUdpd005kyZYqee+45RUREZHcpPmnlypVyOBx6++23M/35MsZo7ty5ioqK0meffabTp08rNDTU4kq95/vvv9eIESPUs2fPGz6if/fdd7vs5zNnzqhfv37q0KGD7r77bmd7oUKFbmhd/xavv/66nnrqKcXGxuq5555TSEiI9uzZoxUrVmjevHlq0aKFpEuBe8SIEYqKilKVKlWyt2gA8BICNwBcZt++ffr++++1ePFi9e3bV/Hx8Ro2bNgNrcHhcOjChQsKCgq6odvNrAoVKmjnzp0aM2aMxo8fn93l3FDeem+OHDkiSR4Fz5UrV+qPP/7Qt99+q+bNm2vx4sXq0aPHddXxb1G5cmVVrlzZ+fjYsWPq16+fKleurG7dumVjZbcGY4zOnz+v4OBgt2UXL17UyJEj1bRpU3399dduy9P/LQDArYpTygHgMvHx8cqbN69at26te+65R/Hx8c5lqampypcvn3r16uX2vKSkJAUFBenJJ590tqWkpGjYsGEqVaqU7Ha7IiMj9fTTTyslJcXluTabTQMHDlR8fLwqVKggu93uPM3y9ddfV506dZQ/f34FBwerevXqGZ6yfe7cOQ0aNEgFChRQaGio2rZtq4MHD8pms2n48OEufQ8ePKgHH3xQhQoVkt1uV4UKFfTBBx9keh9FRUWpe/fumjJlig4dOnTVvj179lRUVJRbe/opvhnthwULFqh8+fIKDg7WnXfeqW3btkmSJk+erFKlSikoKEgNGjRQYmJihtvcuHGj6tSpo+DgYEVHR2vSpElufbzx3lzJe++95+wbERGhAQMGuJxGHRUV5fwSp2DBghm+RxmJj49X+fLl1bBhQzVp0sTls3m5gwcP6qGHHlJERITsdruio6PVr18/Xbhwwdnn5MmTeuKJJxQVFSW73a5ixYqpe/fuLtclZ2UflSlTRkFBQapevbpWr17t7DN8+HA99dRTkqTo6GjnKdyXv4ezZ89W9erVFRwcrHz58qlz5846cOCA2+t7//33FRMTo+DgYNWqVUtr1qy55r7LrG+//Vb16tVTzpw5lSdPHrVr107bt2+/5vN+//13lSpVShUrVtRff/0l6dI+fvzxxxUZGSm73a5SpUpp7NixcjgczuclJibKZrPp9ddfd74uu92umjVr6qeffnLZxp9//qlevXqpWLFistvtKlKkiNq1a3fFfwfpevbsqVy5cum3335T8+bNlTNnTkVEROill16SMcalr8Ph0FtvvaUKFSooKChIhQoVUt++fXXixAmXflFRUWrTpo2WLVumGjVqKDg4WJMnT85w+8eOHVNSUpLq1q2b4fLw8HBJl75QqlmzpiSpV69ezs/IjBkznH3XrVunFi1aKHfu3AoJCVFsbKy+++47l/WlH1t27NihTp06KSwsTPnz59djjz2m8+fPX3VfAYAlDADAqWzZsuahhx4yxhizevVqI8msX7/eufzBBx80efLkMSkpKS7PmzlzppFkfvrpJ2OMMWlpaaZZs2YmJCTEPP7442by5Mlm4MCBJiAgwLRr187luZJMuXLlTMGCBc2IESPMu+++azZv3myMMaZYsWKmf//+ZsKECeaNN94wtWrVMpLM559/7rKOTp06GUnmgQceMO+++67p1KmTuf32240kM2zYMGe/P//80xQrVsxERkaal156yUycONG0bdvWSDJvvvnmNfdPiRIlTOvWrc3evXtNQECAefTRR53LEhISjCSzYMECZ1uPHj1MiRIl3NYzbNgw889fQZJM5cqVTWRkpBkzZowZM2aMyZ07tylevLiZMGGCKV++vBk3bpwZMmSIyZEjh2nYsKHL82NjY01ERIQJDw83AwcONOPHjzd33XWXkWSmTZvm7Oet9yYj6a+rSZMm5p133jEDBw40/v7+pmbNmubChQvGGGM+/vhj06FDByPJTJw40cyaNcts3br1qvv9/PnzJk+ePGbkyJHGGGM+/PBD4+/vbw4fPuzS7+DBgyYiIsL52iZNmmSGDh1qypUrZ06cOGGMMeb06dOmYsWKxt/f3/Tu3dtMnDjRjBw50tSsWdP52jzdRxUrVjQFChQwL730khk7dqwpUaKECQ4ONtu2bTPGGLN161bTpUsX5+ds1qxZZtasWebMmTPGGGNGjRplbDabue+++8x7771nRowYYQoUKGCioqKcdRtjzNSpU40kU6dOHTN+/Hjz+OOPmzx58piSJUua2NjYq+7Dyx09etTt38by5ctNQECAue2228yrr77qrCFv3rxm3759zn7p7/HRo0eNMcbs2bPHFC9e3FSpUsXZdvbsWVO5cmWTP39+8/zzz5tJkyaZ7t27G5vNZh577DHnuvbt22ckmapVq5pSpUqZsWPHmldffdUUKFDAFCtWzPmZMcaYOnXqmNy5c5shQ4aYqVOnmldeecU0bNjQrFq16qqvtUePHiYoKMiULl3aPPDAA2bChAmmTZs2RpIZOnSoS9+HH37YBAQEmN69e5tJkyaZZ555xuTMmdPl82vMpeNAqVKlTN68ec2zzz5rJk2aZBISEjLcflpamgkODjbVq1c3x48fv2Kdf/75p3nppZeMJNOnTx/nZ2Tv3r3GGGO++eYbkyNHDnPnnXeacePGmTfffNNUrlzZ5MiRw6xbt87t/alUqZKJi4szEyZMMN26dXMeHwHgRiNwA8D/27Bhg5Fkli9fbowxxuFwmGLFirn8B3nZsmVGkvnss89cntuqVStTsmRJ5+NZs2YZPz8/s2bNGpd+kyZNMpLMd99952yTZPz8/Mx///tft5qSk5NdHl+4cMFUrFjRNGrUyNm2ceNGI8k8/vjjLn179uzpFioeeughU6RIEXPs2DGXvp07dza5c+d2294/pQduY4zp1auXCQoKMocOHTLGeCdw2+12l3AzefJkI8kULlzYJCUlOdufe+45I8mlb2xsrJFkxo0b52xLSUkxVapUMeHh4c7A4K335p+OHDlicuTIYZo1a2bS0tKc7RMmTDCSzAcffOD2+tMD2rUsXLjQSDK7d+82xhiTlJRkgoKC3L4k6d69u/Hz83N+8XM5h8NhjDHmxRdfNJLM4sWLr9jH030kyWzYsMHZ9vvvv5ugoCDToUMHZ9trr73m9p4ZY0xiYqLx9/c3L7/8skv7tm3bTEBAgLP9woULJjw83FSpUsXlC6/333/fSLruwJ3+Obk8FG7dutX4+fmZ7t27O9suf++2b99uIiIiTM2aNc3ff//t7DNy5EiTM2dOs2vXLpftPvvss8bf39/s37/fGPO/wJ0/f36X53/yyScux5kTJ04YSea1117L9GtM16NHDyPJ5csxh8NhWrdubXLkyOH8DK5Zs8ZIMvHx8S7P/+qrr9zaS5QoYSSZr776KlM1pH/mcubMaVq2bGlefvlls3HjRrd+P/30k5Fkpk+f7tLucDhM6dKlTfPmzZ2fUWMuHR+jo6NN06ZNnW3p70/btm1d1tG/f38j6ZpfbgGAt3FKOQD8v/j4eBUqVEgNGzaUJOds0PPmzVNaWpokqVGjRipQoIDmz5/vfN6JEye0fPlyl5mjFyxYoHLlyqls2bI6duyY86dRo0aSpISEBJdtx8bGqnz58m41XX5N5IkTJ3Tq1CnVq1dPmzZtcrann+Lcv39/l+f+cyZxY4wWLVqkuLg4GWNc6mrevLlOnTrlst5rGTJkiC5evKgxY8Zk+jnX0rhxY5dT0NNniu/YsaPLBGHp7b/99pvL8wMCAtS3b1/n4xw5cqhv3746cuSINm7cKMl7780/rVixQhcuXNDjjz8uP7///Xrt3bu3wsLC9MUXX2RmF2QoPj5eNWrUcE78FRoaqtatW7ucVu5wOLRkyRLFxcWpRo0abutIP4V/0aJFuv3229WhQ4cr9vF0H915552qXr2683Hx4sXVrl07LVu2zPlv50oWL14sh8OhTp06uWyrcOHCKl26tHNbGzZs0JEjR/TII48oR44czuf37NlTuXPnvuo2ruXw4cPasmWLevbsqXz58jnbK1eurKZNm+rLL790e84vv/yi2NhYRUVFacWKFcqbN69z2YIFC1SvXj3lzZvX5TU1adJEaWlpLqfbS9J9993n8vx69epJ+t/nOzg4WDly5NDKlSvdTu/OrIEDBzr/nn4ZwIULF7RixQpnzblz51bTpk1daq5evbpy5crl9p5HR0erefPmmdr2iBEjNGfOHFWtWlXLli3TCy+8oOrVq6tatWqZOmV/y5Yt2r17t7p27arjx487azt79qwaN26s1atXu5yqL0kDBgxweZx+PMzovQQAKzFpGgBISktL07x589SwYUPt27fP2V67dm2NGzdO33zzjZo1a6aAgAB17NhRc+bMUUpKiux2uxYvXqzU1FSXwL17925t375dBQsWzHB7/5woKDo6OsN+n3/+uUaNGqUtW7a4XDt7+fXPv//+u/z8/NzW8c/Zr48ePaqTJ0/q/fffv+JtqDyZwKhkyZJ64IEH9P777+vZZ5/N9POupnjx4i6P04NUZGRkhu3/DB8RERHKmTOnS9ttt90m6dL1snfccYfX3pt/+v333yVJZcqUcWnPkSOHSpYs6VzuqZMnT+rLL7/UwIEDtWfPHmd73bp1tWjRIu3atUu33Xabjh49qqSkpGvei3zv3r3q2LHjVft4uo9Kly7t1ue2225TcnKyjh49qsKFC191W8aYDNchSYGBgZL+t3//2S8wMFAlS5a88ovJhCu9d5JUrlw5LVu2TGfPnnX5bMXFxalQoUJatmyZcuXK5fKc3bt36+eff870/vvn5z49fKd/vu12u8aOHav//Oc/KlSokO644w61adNG3bt3v+q+Tefn5+e2jy7/d5Fe86lTp5zXVF+r5sz+u0jXpUsXdenSRUlJSVq3bp1mzJihOXPmKC4uTr/88stVJyLcvXu3JF11ksBTp065fGnxz89JTEyM/Pz8rnnNOwB4G4EbAHRpsqTDhw9r3rx5mjdvntvy+Ph4NWvWTJLUuXNnTZ48WUuXLlX79u310UcfqWzZsrr99tud/R0OhypVqqQ33ngjw+39M0BmNLvvmjVr1LZtW9WvX1/vvfeeihQposDAQE2fPl1z5szx+DWmjwB169btiv9xvXwm58x44YUXNGvWLI0dO1bt27d3W/7PidHSXWnU09/f36N2849JnzLDG+/NjbRgwQKlpKRo3LhxGjdunNvy+Ph4jRgxwqvb9HQfXe+2bDabli5dmuH7/M8we7Po2LGjZs6cqfj4eJezKqRLr6lp06Z6+umnM3xuethNl5nP9+OPP664uDgtWbJEy5Yt09ChQzV69Gh9++23qlq16nW+mks1h4eHX3Eyvn9+eZDVfxdhYWFq2rSpmjZtqsDAQM2cOVPr1q1TbGzsVWuTpNdee+2Ktwu71ufkSsciALAagRsAdCm0hIeH691333VbtnjxYn388ceaNGmSgoODVb9+fRUpUkTz58/XXXfdpW+//VYvvPCCy3NiYmK0detWNW7cOMv/0Vu0aJGCgoK0bNky2e12Z/v06dNd+pUoUUIOh0P79u1zGdW5fDRUuvQf5tDQUKWlpalJkyZZqumfYmJi1K1bN02ePNl5mvfl8ubN6zJDd7qsjvZey6FDh9xGInft2iVJzlPVvfHeZKREiRKSpJ07d7qMJl64cEH79u3L8j6Pj49XxYoVM7w93eTJkzVnzhyNGDFCBQsWVFhYmH755Zerri8mJiZTfTzZR+kjkJfbtWuXQkJCnEHtSuuJiYmRMUbR0dFuQfRy6ft39+7dzlPbpUt3D9i3b5/LF16euvy9+6cdO3aoQIECbmdOvPbaawoICFD//v0VGhqqrl27urymM2fOeO3f2eXr/c9//qP//Oc/2r17t6pUqaJx48Zp9uzZV32ew+HQb7/95rJ/M/p3sWLFCtWtW/eGfclUo0YNzZw5U4cPH5Z09c+IdCmsZ3af7t6922UUfs+ePXI4HBneNQEArMQ13AD+9c6dO6fFixerTZs2uueee9x+Bg4cqNOnT+vTTz+VdOn0zHvuuUefffaZZs2apYsXL7qcTi5JnTp10sGDBzVlypQMt3f27Nlr1uXv7y+bzeYyGpyYmKglS5a49Eu/jvK9995zaX/nnXfc1texY0ctWrQow8B19OjRa9aUkSFDhig1NVWvvvqq27KYmBidOnVKP//8s7Pt8OHD+vjjj7O0rWu5ePGiy+2JLly4oMmTJ6tgwYLOa4y98d5kpEmTJsqRI4fGjx/vMjI5bdo0nTp1Sq1bt/Z4nQcOHNDq1avVqVOnDD+bvXr10p49e7Ru3Tr5+fmpffv2+uyzz7Rhwwa3daXX1LFjR23dujXD9yC9j6f76IcffnC5/v/AgQP65JNP1KxZM+fobXpg/ecXMHfffbf8/f01YsQItzMWjDE6fvy4pEvhrGDBgpo0aZLLLc5mzJiR4Zc6nihSpIiqVKmimTNnuqzrl19+0ddff61WrVq5Pcdms+n999/XPffcox49ejiPD9Kl/ffDDz9o2bJlbs87efKkLl686FF9ycnJbre0iomJUWhoqNtt2q5kwoQJzr8bYzRhwgQFBgaqcePGzprT0tI0cuRIt+devHgxy/s4OTlZP/zwQ4bLli5dKul/p/Jf6TNSvXp1xcTE6PXXX9eZM2fc1pPRseufX56mHw9btmzp2QsAgOvECDeAf71PP/1Up0+fVtu2bTNcfscdd6hgwYKKj493Buv77rtP77zzjoYNG6ZKlSqpXLlyLs954IEH9NFHH+mRRx5RQkKC6tatq7S0NO3YsUMfffSR8/61V9O6dWu98cYbatGihbp27aojR47o3XffValSpVwCbPXq1dWxY0e99dZbOn78uO644w6tWrXKOYJ1+ajRmDFjlJCQoNq1a6t3794qX768/v77b23atEkrVqzQ33//7fH+Sx/lnjlzptuyzp0765lnnlGHDh00aNAgJScna+LEibrttts8mqAtsyIiIjR27FglJibqtttu0/z587Vlyxa9//77zmuBvfHeZKRgwYJ67rnnNGLECLVo0UJt27bVzp079d5776lmzZrq1q2bx+ucM2eOjDFX/Gy2atVKAQEBio+PV+3atfXKK6/o66+/VmxsrPr06aNy5crp8OHDWrBggdauXas8efLoqaee0sKFC3XvvffqwQcfVPXq1fX333/r008/1aRJk3T77bd7vI8qVqyo5s2ba9CgQbLb7c4vfy4/1T39C48XXnhBnTt3VmBgoOLi4hQTE6NRo0bpueeeU2Jiotq3b6/Q0FDt27dPH3/8sfr06aMnn3xSgYGBGjVqlPr27atGjRrpvvvu0759+zR9+vTrvoZbujRi3bJlS91555166KGHdO7cOb3zzjvKnTv3Fe+T7ufnp9mzZ6t9+/bq1KmTvvzySzVq1EhPPfWUPv30U7Vp00Y9e/ZU9erVdfbsWW3btk0LFy5UYmKiChQokOnadu3apcaNG6tTp04qX768AgIC9PHHH+uvv/5S586dr/n8oKAgffXVV+rRo4dq166tpUuX6osvvtDzzz/vPAMhNjZWffv21ejRo7VlyxY1a9ZMgYGB2r17txYsWKC3335b99xzT6ZrTpecnKw6derojjvuUIsWLRQZGamTJ09qyZIlWrNmjdq3b+88JT4mJkZ58uTRpEmTFBoaqpw5c6p27dqKjo7W1KlT1bJlS1WoUEG9evVS0aJFdfDgQSUkJCgsLEyfffaZy3b37duntm3bqkWLFvrhhx80e/Zsde3a9brOhACALMmWudEB4CYSFxdngoKCzNmzZ6/Yp2fPniYwMNB5Oy2Hw2EiIyONJDNq1KgMn3PhwgUzduxYU6FCBWO3203evHlN9erVzYgRI8ypU6ec/SSZAQMGZLiOadOmmdKlSxu73W7Kli1rpk+fnuEttc6ePWsGDBhg8uXLZ3LlymXat29vdu7caSSZMWPGuPT966+/zIABA0xkZKQJDAw0hQsXNo0bNzbvv//+NffV5bcFu9zu3buNv7+/223BjDHm66+/NhUrVjQ5cuQwZcqUMbNnz77ibcH+uR/Sb5v0z9shZXQLstjYWFOhQgWzYcMGc+edd5qgoCBTokQJM2HCBLd6vfHeXMmECRNM2bJlTWBgoClUqJDp16+fy72kjcn8bcEqVapkihcvftU+DRo0MOHh4SY1NdUYc+mWXN27dzcFCxY0drvdlCxZ0gwYMMDlVlrHjx83AwcONEWLFjU5cuQwxYoVMz169HC5XZyn+2j27NnOz2rVqlUzvC/zyJEjTdGiRY2fn5/bLcIWLVpk7rrrLpMzZ06TM2dOU7ZsWTNgwACzc+dOl3W89957Jjo62tjtdlOjRg2zevVqExsbe923BTPGmBUrVpi6deua4OBgExYWZuLi4syvv/7q0iej9y45OdnExsaaXLlymR9//NEYc+l+588995wpVaqUyZEjhylQoICpU6eOef311523qLvS5zt9v6bXd+zYMTNgwABTtmxZkzNnTpM7d25Tu3Zt89FHH13ztfbo0cPkzJnT7N2713lv9UKFCplhw4a53L4u3fvvv2+qV69ugoODTWhoqKlUqZJ5+umnnbf/M+bKx4GMpKammilTppj27dubEiVKGLvdbkJCQkzVqlXNa6+95vK5NObSLdHKly9vAgIC3G4RtnnzZnP33Xeb/PnzG7vdbkqUKGE6depkvvnmG2ef9Pfn119/Nffcc48JDQ01efPmNQMHDjTnzp3LVM0A4E02Y7Iw4wwA4Ka3ZcsWVa1aVbNnz9b999+f3eXgFmWz2TRgwACXU5Zx8+jZs6cWLlyY4anYt6Lhw4drxIgROnr0qEdnEQCAVbiGGwBuAefOnXNre+utt+Tn56f69etnQ0UAAADgGm4AuAW8+uqr2rhxoxo2bKiAgAAtXbpUS5cuVZ8+fbx6CycAAABkHoEbAG4BderU0fLlyzVy5EidOXNGxYsX1/Dhw91uVwYAAIAbh2u4AQAAAACwANdwAwAAAABgAQI3AAAAAAAWIHADAAAAAGABAjcA4KpmzJghm82mDRs2XLFPYmKibDabXn/99auuKyoqSjabTU2aNMlw+ZQpU2Sz2a65vasZPny4bDabjh07dsU+K1eulM1m08KFCzO93k6dOslms+mZZ5656jptNptmz56dYZ+6devKZrOpYsWKGS5PS0tTRESEbDabli5dmunaJOmJJ55QtWrVlC9fPoWEhKhcuXIaPnx4pu+/PHHiRN17770qXry4bDabevbs6dH209/bjH5Kly7t1n/atGkqV66cgoKCVLp0ab3zzjtufXr27OmynoCAAEVGRqpz58769ddfM1VXZj6/1+PXX3/V8OHDlZiYaMn6faUGAEDGmKUcAHBDBQUFKSEhQX/++acKFy7ssiw+Pl5BQUE6f/58NlWXsaSkJH322WeKiorS3LlzNWbMGNlstgz7BgUFac6cOerWrZtLe2Jior7//nsFBQVdcTvffvutDh8+rKioKMXHx6tly5aZrvGnn35SvXr11KtXLwUFBWnz5s0aM2aMVqxYodWrV8vP7+rfsY8dO1anT59WrVq1dPjw4UxvN91bb73lFu5///13DRkyRM2aNXNpnzx5sh555BF17NhRgwcP1po1azRo0CAlJye7faFht9s1depUSdLFixe1d+9eTZo0SV999ZV+/fVXRUREeFyrN/36668aMWKEGjRooKioqH9tDQCAjBG4AQA3VN26dfXTTz9p/vz5euyxx5ztf/zxh9asWaMOHTpo0aJF2Vihu0WLFiktLU0ffPCBGjVqpNWrVys2NjbDvq1atdKnn36qY8eOqUCBAs72OXPmqFChQipdurROnDiR4XNnz56tatWqqUePHnr++ed19uxZ5cyZM1M1rl271q0tJiZGTz75pNavX6877rjjqs9ftWqVc3Q7V65cmdrm5dq3b+/WNmrUKEnS/fff72w7d+6cXnjhBbVu3dp5hkHv3r3lcDg0cuRI9enTR3nz5nX2DwgIcPvy4o477lCbNm30xRdfqHfv3h7Xml2MMTp//ryCg4OzuxQAwA3CKeUAgBsqKChId999t+bMmePSPnfuXOXNm1fNmzd3e05qaqp27NiRpZFXb4iPj1fTpk3VsGFDlStXTvHx8Vfs265dO9ntdi1YsMClfc6cOerUqZP8/f0zfN65c+f08ccfq3PnzurUqZPOnTunTz755LrqTh/tPHny5DX7lihR4oqj9lk1Z84cRUdHq06dOs62hIQEHT9+XP3793fpO2DAAJ09e1ZffPHFNdebfmZEQEDWxg169uypXLly6eDBg2rfvr1y5cqlggUL6sknn1RaWppL33nz5ql69eoKDQ1VWFiYKlWqpLffflvSpdPV7733XklSw4YNnae+r1y5UtKl/d+mTRstW7ZMNWrUUHBwsCZPnuy8BGPGjBlutdlsNg0fPtyl7eDBg3rooYcUEREhu92u6Oho9evXTxcuXLhmDQCA7EXgBgDccF27dtX69eu1d+9eZ9ucOXN0zz33KDAw0K3/wYMHVa5cOT333HM3skxJ0qFDh5SQkKAuXbpIkrp06aKFCxfqwoULGfYPCQlRu3btNHfuXGfb1q1b9d///lddu3a94nY+/fRTnTlzRp07d1bhwoXVoEGDqwb7jFy8eFHHjh3ToUOH9PXXX2vIkCEKDQ1VrVq1PFqPN2zevFnbt293e82bN2+WJNWoUcOlvXr16vLz83Muv9yxY8d07Ngx/fXXX/rhhx/0xBNPKH/+/GrTpk2W60tLS1Pz5s2VP39+vf7664qNjdW4ceP0/vvvO/ssX75cXbp0Ud68eTV27FiNGTNGDRo00HfffSdJql+/vgYNGiRJev755zVr1izNmjVL5cqVc65j586d6tKli5o2baq3335bVapU8ajOQ4cOqVatWpo3b57uu+8+jR8/Xg888IBWrVql5OTkTNUAAMg+nFIOALjhGjVqpMKFC2vu3LkaMmSItm/fri1btujtt9/Wb7/9lt3luZg7d67sdrvatWsnSercubNefPFFffnllxmeRi1d+kIhLi5OBw4cUGRkpOLj41WyZMmrntY9e/Zs1alTR5GRkc7t9O/fX0ePHlXBggUzVeuGDRt05513Oh+XKVNGn376qfLly5fJV+s96V8WXH46uSQdPnxY/v7+Cg8Pd2nPkSOH8ufPr0OHDrm0nz171u31Fy1aVF9//XWm90tGzp8/r/vuu09Dhw6VJD3yyCOqVq2apk2bpn79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cLda06/hTkxMdDu9/vKfy61bt04tWrRQ7ty5FRISotjYWH333XcufU6fPq3HH39cUVFRstvtCg8PV9OmTbVp0yZnn+TkZO3YsUPHjh275utK9+qrr8rhcOjJJ5/M9HOuJCkpSUFBQcqTJ49Le5EiRRQcHHzd6wcA4J8Y4QYA/OucOnVKx44dkzFGR44c0TvvvKMzZ86oW7duLv3efvtttW3bVvfff78uXLigefPm6d5779Xnn3+u1q1bS5JmzZqlhx9+WLVq1VKfPn0kSTExMZKkQ4cOqVatWjp58qT69OmjsmXL6uDBg1q4cKGSk5NdQvKjjz6qvHnzatiwYUpMTNRbb72lgQMHav78+Vd9LSVKlNA333yjP/74Q8WKFcv0PihYsKBmzZrl0paamqonnnjCpa5vv/1WLVu2VPXq1TVs2DD5+flp+vTpatSokdasWaNatWpJkh555BEtXLhQAwcOVPny5XX8+HGtXbtW27dvV7Vq1SRJ69evV8OGDTVs2LBMTd62f/9+jRkzRh988IFXAnGDBg00f/589e3bV4MHD3aeUr548WK99tpr171+AADcGAAA/iWmT59uJLn92O12M2PGDLf+ycnJLo8vXLhgKlasaBo1auTSnjNnTtOjRw+353fv3t34+fmZn376yW2Zw+FwqalJkybONmOMeeKJJ4y/v785efLkVV/TtGnTjCSTI0cO07BhQzN06FCzZs0ak5aW5tZXkhk2bNgV19W/f3/j7+9vvv32W2eNpUuXNs2bN3epLTk52URHR5umTZs623Lnzm0GDBhw1VoTEhKuWcPl7rnnHlOnTh2X+q+1jau5ePGiGThwoAkMDHS+9/7+/mbixIlZXicAAFfDCDcA4F/n3Xff1W233SZJ+uuvvzR79mw9/PDDCg0N1d133+3sd/mo6okTJ5SWlqZ69epp7ty519yGw+HQkiVLFBcX53K9eLp/nrbdp08fl7Z69erpzTff1O+//67KlStfcTsPPvigihYtqjfeeEMJCQlKSEjQyJEjVbJkSc2aNUt16tS5Zq2S9OGHH+q9997TuHHj1LBhQ0nSli1btHv3bg0ZMkTHjx936d+4cWPNmjVLDodDfn5+ypMnj9atW6dDhw4pIiIiw200aNBAxphM1ZOQkKBFixZp3bp1meqfGf7+/oqJiVHz5s117733KigoSHPnztWj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evfddzVv3jyFhoaajgMARXbz5k1lZ2fLx8fHdBQAKBFxcXHq1KmTLl26pPvvv1+xsbEaPHiwTp8+LTc3N126dElffvml2rZtazoqXByFG7AjMDBQ6enpunXrlnx8fPJtmpaammooGQAAANLS0nT06FHVqlVL9913n27cuKFly5YpIyND7dq1U61atUxHBCjcgD2LFy++6/qAAQPuURIAKHldunTRggULVLVqVdNRAAAosyjcAAC4oAoVKighIUHh4eGmowBAiahfv76++uorBQcHm44C5GKXcqAAbty4oczMTJtzbKgGAADgOE6dOqWsrCzTMQAb7FIO2JGWlqYRI0YoKChIvr6+CgwMtPkHAJxZSEhIvr0pAABAyaJwA3aMGzdOW7Zs0dy5c1WuXDktWLBAkydPVrVq1bRkyRLT8QCgWA4fPsxtlwDKlBYtWsjb29t0DMAGz3ADdlSvXl1LlizRY489Jj8/P8XHx6tmzZpaunSpli9frq+++sp0RAAolJycHLm55Z+15+Tk6KeffuJd3AAAlDCucAN2pKam5m4m5Ofnl/sasObNm2v79u0mowFAoVy9elW9evWSr6+vKleurAkTJig7Ozt3/fz58woLCzOYEABK1qVLl7gjEQ6Bwg3YER4erpMnT0qSateurRUrVkiSvvzySwUEBBhMBgCF89prrykhIUFLly7V1KlTtWTJEj355JM2m0FywxuAsiQpKUkDBw40HQPglnLAnrfeekvu7u4aOXKkvv76az3xxBOyWq3KysrSrFmzNGrUKNMRAaBAQkJCtHjxYj322GOSpAsXLqhLly4KCAjQmjVrdPnyZVWrVs3mqjcAOLKrV6/edf3gwYNq1aoV32swjsINFNDp06e1b98+1axZUw0aNDAdBwAKzMfHR999953NbePXrl1Thw4d5O3trQULFqhmzZr8YArAabi5uclisdhdt1qtslgsfK/BOAo3AABlXO3atTVr1ix17tzZ5vz169fVvn17paen69ChQ/xgCsBp+Pv76y9/+YuaNGlyx/Xjx4/rxRdf5HsNxnmYDgA4ktmzZxf4syNHjizFJABQctq3b6+FCxfmK9z33XefNm7cqHbt2hlKBgBFExUVJUlq1arVHdcDAgLYmwIOgSvcwK8UdJdei8WixMTEUk4DACXj0qVL+s9//qPf/va3d1y/du2a4uPj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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "accepted_lengths = []\n", + "\n", + "for ssm in small_model_names:\n", + " for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/specinfer_llm_meta-llama-Llama-3.1-70B-Instruct_ssm_{model_name}_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " accepted_lengths.append({\n", + " 'Model': model_name,\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'Accepted Length': get_accepted_len(filepath)\n", + " })\n", + "\n", + "accepted_df = pd.DataFrame(accepted_lengths)\n", + "\n", + "# # Create a bar plot\n", + "# fig, ax = plt.subplots(figsize=(12, 8))\n", + "# accepted_df.pivot_table(index=['Model', 'Batch Size'], columns='Arrival Rate', values='Accepted Length').plot(kind='bar', ax=ax)\n", + "# plt.title('Accepted Length by Model, Batch Size, and Arrival Rate')\n", + "# plt.ylabel('Accepted Length')\n", + "# plt.xlabel('Model and Batch Size')\n", + "# plt.legend(title='Arrival Rate')\n", + "# plt.show()\n", + "# Group by model and calculate the mean of accepted lengths\n", + "average_accepted_df = accepted_df.groupby('Model')['Accepted Length'].mean().reset_index()\n", + "\n", + "# Sort the dataframe by 'Accepted Length' in ascending order\n", + "average_accepted_df = average_accepted_df.sort_values(by='Accepted Length')\n", + "\n", + "# Create a bar plot\n", + "fig, ax = plt.subplots(figsize=(12, 8))\n", + "average_accepted_df.plot(x='Model', y='Accepted Length', kind='bar', ax=ax)\n", + "plt.title('Average Number of Accepted Tokens per Step\\nLLM: LLAMA-3.1-70B-Instruct\\nBatch Sizes: 4, 8')\n", + "plt.ylabel('Average Number of Accepted Tokens')\n", + "plt.xlabel('Model')\n", + "plt.grid(True) # Turn the grid on\n", + "\n", + "# Save the plot as a PDF\n", + "plt.savefig('/usr/FlexFlow/wildchat/average_accepted_tokens.pdf')\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB8UAAAHvCAYAAADNQw6XAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1gUV9sG8HupSwcVRBABkfiCXewNsCEidrELRmOPGjUajQXFGnvXaAKKEOy9koixJZbYYi8RNTZEpQhSd74/+HbisksVXBbv33VxwZ45M/PM7DqP8Mw5IxEEQQAREREREREREREREREREVEppKXuAIiIiIiIiIiIiIiIiIiIiIoLi+JERERERERERERERERERFRqsShORERERERERERERERERESlFoviRERERERERERERERERERUarEoTkREREREREREREREREREpRaL4kREREREREREREREREREVGqxKE5ERERERERERERERERERKUWi+JERERERERERERERERERFRqsShORERERERERERERERERESlFoviRERERERUYp04cQISiQQ7duxQdyiFEh0dDYlEgkWLFqk7FCoi7969w+DBg2FtbQ2JRIKxY8eqOyQlEokEgYGBCm0XLlxAkyZNYGRkBIlEgitXrgAAjhw5gtq1a0MqlUIikSAuLu6Tx6upAgMDIZFIinUfDg4OCAgIKNZ9EBERERERfQ5YFCciIiIiok9KIpHk6+vEiRPqDlXjHTp0SKk4qg7y4mFeXx4eHgCAgIAAhXZTU1PUqlULixcvRmpqqtL2z5w5gy5duqB8+fLQ19eHg4MDhg4disePH4t95Dco5OcrOjo6x2OZO3cuQkJCMHz4cISGhqJ///5FfboUODg4iHFpaWnB3NwcNWrUwJAhQ3Du3Ll8bSM9PR09evTAmzdvsHTpUoSGhsLe3h6vX7+Gn58fDAwMsHr1aoSGhsLIyKhYj6ewnj17hsDAQLGYXxBr1qyBRCJBw4YNiz6wEiL7Z9jU1BTu7u44ePBgobcZHh6OZcuWFV2QREREREREaqSj7gCIiIiIiOjzEhoaqvB68+bNiIyMVGp3cXHBrVu3PmVopc6hQ4ewevVqtRfGu3btiipVqoiv3717h+HDh6NLly7o2rWr2F6+fHnxZ319fWzcuBEAEBcXh507d2LChAm4cOECIiIi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/P7770rL+/XrByCr4PzHH38gKCgIq1atwrt372BtbY2GDRuK58vQ0BAjRozAsWPHsGvXLshkMlSpUgVr1qzB8OHDi+Q4cyOPKS99+/ZFuXLlMG/ePCxcuBAJCQmoWrUq1q1bp/DeExERERERERUHiVBU88YRERERERER0WcjMTERZcqUwbJlyzBy5Eh1h0NERERERESUIz5TnIiIiIiIiIgK7OTJk7C1tcVXX32l7lCIiIiIiIiIcsWR4kREREREREREREREREREVGpxpDgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosihMRERERERERERERERERUanFojgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosihMRERERERERERERERERUanFojgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosihMRERERERERERERERERUanFojgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosihMRERERERERERERERERUanFojgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosihMRERERERERERERERERUanFojgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosihMRERERERERERERERERUanFojgREREREREREREREREREZVaLIoTEREREREREREREREREVGpxaI4ERERERERERERERERERGVWiyKExERERERERERERERERFRqcWiOBERERERERERERERERERlVosilOpFxgYCIlEUqz7cHBwQEBAQLHuQxMtXLgQlStXhra2NmrXrg0AyMjIwMSJE2FnZwctLS107twZACCRSBAYGCiuGxISAolEgujo6E8eNxEVL16XiYgoO+YGIiLKjrmBiIg+xLxARB+LRXEqMdasWQOJRIKGDRuqO5RiI5FIFL5MTU3h7u6OgwcPFnqb4eHhWLZsWdEFWUSOHTuGiRMnomnTpggODsbcuXMBAD///DMWLlyI7t27Y9OmTfjmm2/UHCkR5YTX5cL51NflY8eOYdCgQahevTq0tbXh4ODwyfatCW7evInAwMCPvslq/PjxcHV1LZqgiDQYc0PhfMrckJycjNWrV6Nt27aoUKECTExMUKdOHaxduxaZmZmfJIaSjrmBqGgxNxSOOv+eExcXBysrK0gkEuzYsUMtMZQ0Z8+eRWBgIOLi4j5qO926dUP79u2LJigiDcW8UDifOi/IZDKsW7cOtWvXhrGxMcqXLw9vb2+cPXv2k8VQkjEvlE4silOJERYWBgcHB5w/fx73798vsu1OnToV79+/L7Ltfaw2bdogNDQUmzdvxsSJE3H//n34+vri6NGjhdpeSS2KHz9+HFpaWvjpp58wYMAA8cJ//Phx2NraYunSpejfvz/c3d1Vrt+/f3+8f/8e9vb2nzJsIvoAr8uacV0ODw9HeHg4zMzMYGNj88n2qylu3ryJmTNnfnTh4+DBg/Dx8SmaoIg0GHNDyc8N//zzD77++msIgoBx48Zh0aJFcHR0xIgRI/Dll19+khhKOuYGoqLF3FDyc0N206dPR3Jyslr2XVKdPXsWM2fO/KjiR3p6OiIjI5kb6LPHvKAZeeHbb7/F8OHDUaNGDSxZsgTjx4/H3bt34e7ujvPnz3+yOEoq5oXSiUVxKhEePnyIs2fPYsmSJbC0tERYWFi+1svIyEBaWprKZUlJSQAAHR0dSKXSIov1Y33xxRfo168f+vfvj6lTp+LXX3+FIAhYvny5ukMrUjExMTAwMICenp5Su7m5eZ7ra2trQyqVFvuUOESkGq/LmnNdnjt3LhISEnDmzBnUqlXro7eX23v4ufrnn39w584d/hJDnz3mBs3IDdbW1vj7778RGRmJ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66wCNhgMWLBggfJ2hw4d8Mcff+Drr7/G1KlT7a61vtr7RiclJeHpp5/GnXfeiddff12532w244033kCnTp0AANdffz0+/vhj5OTkIDAwEKmpqRg6dCjWrVunNCFvu+025eM7duyIJUuWoG/fvigtLUVgoHN+9iZOnFjn7ffeew9RUVHIyMioM05ozpw5GDVqFADg/vvvx+TJk7F27VpceumlAIDp06fXWVF85ZVX1jnu0qVLERoail9++QVXXXVVszU9/PDDeO2112AymTBgwAC7m70AkJeXh6eeegq333673R/TnKKiIuVrXV5eDqPRiJdffln5Pjpi2rRpmDx5MgBg4cKFWLJkCbZs2YLRo0cjMzMT6enp6NOnDwDbz5EsKioKABAREdFgVXtAQADeeecdeHt7213H8uXLcfbsWWzdulW5QrZz587K+wMDA+Hl5dXsCnp3ETaXuFKciMhlhMsGqwWoqrkokCvFiYicTrhcqK+8Zk9xNsWJiJxGuGxQzhc8cKtWIiI3cXil+NNPP40333wTb7/9dp1VmZdeeqldY4/bDLkhDmh/pbhAevbsqfzbYDAgIiICaWlpyn0xMTEAgNzcXOzatQvr1q1DYGCg8l9KSgoA1Bn93Zh///vfuOSSSxAVFYXAwEC8/fbbOHXqFADbFYS1j7ls2TK7al+zZg2GDRuGiy66CEFBQbj55puRn58Pk8mkPMbf379OIzUmJgZJSUl1mtsxMTF1xqNv374d48ePR2JiIoKCgnDFFVcAADIzMwEAaWlpaNeuHYKDgzFmzBi7aq3v0KFDmDx5Mjp27Ijg4GClGSs/h6z290f+XtT//tSuPScnBzNmzEBycjJCQkIQHByM0tJS5bgzZ85Uaq/f4H/wwQfx559/4qeffoLBYMAtt9wCyY7JA8XFxRg3bhxSU1Mxf/585f7u3bsr31NHv05BQUHYuXMndu7ciT///BPPPPMMZs+ejf/9738AbM3t2j8z9b9utdX+GgYEBCA4OFj5ms2cORMrVqzAxRdfjIceegh//PGHXfWlpaU51BAHgF27diE9PV27I6NqETaXKgptt1wpTkTkdMJlgzw6HQB82RQnInI24XKhPhOb4kREziZcNigrxdlrICJqKYdXih84cACDBw9ucH9ISAgKCwudUZNnkEen6/SA0U/dWi7E6G9bsW2PE38Ay66/8ONu+i/QflCDu61WK4pLShAcFAS9Xm97bkdKrTceW6fT1blPp9Mpz1NaWorx48fjueeea3CcuLi4Jp9jxYoVmDNnDl588UUMHDgQQUFBeP7557Fx40YAQJ8+fbBz507l8XLztznHjx/HVVddhZkzZ+KZZ55BeHg4fv/9d0yfPh1VVVXw9/e36/OT75PHlpeVlWHUqFEYNWoUli1bhqioKGRmZmLUqFGoqqoCAKxcuRLnzp1DYGAgAgJa9j9N48ePR/v27fH2228jPj4eVqsVPXr0UJ5D1tj3ov59tUeuT506Ffn5+XjllVfQvn17+Pj4YODAgcpxFyxYgDvuuAOBgYG2n5daIiMjERkZiS5duqBbt25ISEjApk2bMHDgwCY/j5KSEowePRpBQUH46quv6tT2/fffK3uS+/k59jur1+vrrKLu0aMHfvjhB/zrX//CNddcgzvvvFMZ2w/Y9itqSnPf7zFjxuDEiRP4/vvvsXr1agwbNgx33303XnjhhWbra+z7rtPpGlxEUHtPdke/BmoSNpfkleK+oaqWQUTkiYTLBnl0usEH8PJRtxYiIg8kXC7Up4xP1/5Fy0REohAuG6o4Pp2IqLUcborHxsbi8OHDdcb2AsDvv/+Ojh07Oqsu8VXVGp1e0xzULJ3O/ivMOl0JBMcDxVlofF9xne39na4E9IaG77ZaAaPF9nz6Fm1pb7fevXvjiy++QFJSUpP7Rnt7e8NisdS5b8OGDRg0aBDuuusu5b6jR48q//bz86vTALXH9u3bYbVa8eKLLyrN3c8++8yhYzRm//79yM/Px6JFi5CQYBtZv23btjqPad++PcLCwhAcHNygsWyP/Px8HDhwAG+//TYuv/xyAHDavjobNmzA66+/jrFjxwIATp48iby8POX90dHR8PX1vWDtctNYHnPUmOLiYowaNQo+Pj749ttv4evrW+f97du3b82n0oBer0d5eTkAIDw83GkrrqOiojB16lRMnToVl19+OR588EG88MILykrw+j/PzR0nKytLefvQoUN1phakpaXh3XffRUFBQaO1N/a7oxZhc6m80HbLleJERE4nXDZUcj9xIiJXEi4Xaqsy2ba9A7hSnIjIiYTLBrnf4MOmOBFRSzncIZsxYwbuv/9+bN68GTqdDmfOnMGyZcswZ84czJw50xU1iqnKQ8eZ6A3AaHnldf1mf83boxc13hB3s7vvvhsFBQWYPHkytm7diiNHjuDHH3/ErbfeqjTzkpKSsHnzZhw/fhx5eXmwWq1ITk7Gtm3b8OOPP+LgwYOYN28etm7d2qpaOnfuDLPZjFdffRVHjx7Fxx9/jDfffLPVn2NiYiK8vb2V43777bd46qmn7P743bt3K2O/d+7ciV27djV4TFhYGCIiIrB06VIcPnwYP//8M2bPnt3q2gEgOTkZH3/8Mfbt24fNmzfjpptuuuAK5c2bN+O1117Dzp07ceLECfz888+YPHkyOnXqpKwSP336NFJSUrBlyxYAtob4yJEjUVZWhnfffRfFxcXIzs5Gdnb2BRu7GRkZ2LlzJwoKClBUVKR8rWqTJEk53rFjx7B06VL8/PPPuPrqq1v+xWnE448/jm+++QaHDx/G3r17sXLlSnTr1g2A7QICPz8/rFq1Cjk5OSgqKmr2WFdeeSVee+01/Pnnn9i2bRvuvPPOOqvUJ0+ejNjYWEyYMAEbNmzA0aNH8cUXXygTE5KSknDs2DHs3LkTeXl5zV6Q4GrC5pKypzib4kREziZcNsgrxTk6nYjIJYTLhdrk/cT1Ru4jS0TkRMJlQ2XNnuLezAIiopZyuCn+yCOPYMqUKRg2bBhKS0sxePBg/P3vf8cdd9yBe++916FjPfvss+jbty+CgoIQHR2NCRMm4MCBA3UeU1FRgbvvvhsREREIDAzExIkTkZOTU+cxmZmZGDduHPz9/REdHY0HH3wQ1dXVjn5qzuXJe3ykXg3c8BEQXG8EeXC87f5U5zYCWyo+Ph4bNmyAxWLByJEjkZaWhgceeAChoaHKquM5c+bAYDAgNTVVGT1+xx134LrrrsOkSZPQv39/5Ofnt/p/hHr16oXFixfjueeeQ48ePbBs2TI8++yzrf4co6Ki8MEHH+Dzzz9HamoqFi1adMFR2rUNHjwY6enpyn+XXHJJg8fo9XqsWLEC27dvR48ePTBr1iz861//anXtAPDuu+/i3Llz6N27N26++Wbcd999iI6ObvZj/P398eWXX2LYsGHo2rUrpk+fjp49e+KXX36Bj49t3KjZbMaBAweUlc87duzA5s2bsXv3bnTu3BlxcXHKfydPnmz2+caOHYv09HT873//w/r165WvVW3FxcXK8bp164aXXnoJjz76KB577LFWfHUa8vb2xqOPPoqePXti8ODBMBgMWLFiBQDAy8sLS5YswVtvvYX4+Hhcc801zR7rxRdfREJCAi6//HJMmTIFc+bMUcb4y8/1008/ITo6GmPHjkVaWhoWLVoEg8F2wcvEiRMxevRoDB06FFFRUfj000+d+rk6wpm55FZcKU5E5DLCZYO8UtyHTXEiIlcQLhdqU0anR2h/EiERkUCEywZ5ER5XihMRtZjD49N1Oh3++c9/4sEHH8Thw4dRWlqK1NRUBAY6/sf4l19+wd13342+ffuiuroajz32GEaOHImMjAxlD9xZs2bhu+++w+eff46QkBDcc889uO6667BhwwYAtlHB48aNQ2xsLP744w9kZWXhlltugdFoxMKFCx2uyWmU8eke2BQHbI3vlHG2PcZLc4DAGNse4i5cIb5+/foG9x0/frzBfbX3SU5OTsaXX37Z5DG7dOmirHyt7f3338f777+vvG21WvHII484VF/92mbNmoVZs2bVue/mm29W/j1t2jRMmzatzvvnz5+P+fPn17nvgw8+qPP25MmTMXny5Dr31d8rur4hQ4Y0+5j6zzF8+HBkZGQ0+RxJSUkNjtfYc9T/HNPT0xuswr/++ub3rE9LS8PPP//c7GPq13Ohz7c5jf2M1dbY981qtaK4uFhpINt77MZqrL2H0dy5czF37twmj/f3v/8df//73+vcV/97KYuPj8ePP/7Y4Lnk2gHbSPn//ve/jX68j49Pk+9zN2fmklspK8VDVS2DiMgTCZcNXClORORSwuVCbbWb4kRE5DTCZUMl9xQnImoth5viMm9vb6SmpqK4uBhr1qxB165dlTG+9lq1alWdtz/44ANER0dj+/btGDx4MIqKivDuu+9i+fLluPLKKwHYmpXdunXDpk2bMGDAAPz000/IyMjAmjVrEBMTg4svvhhPPfUUHn74YcyfP1/ZZ9ftlPHpHjzORG8AOlyudhVERACck0tuxfHpREQuJ0w2VNRse8KV4kRELiVMLtRmqhmf7h+ubh1ERB5KiGywmAFLzdaFXClORNRiDjfFb7jhBgwePBj33HMPysvL0bdvXxw7dgySJGHFihWYOHFii4uR98AND7f9j/727dthNpsxfPhw5TEpKSlITEzExo0bMWDAAGzcuBFpaWmIiYlRHjNq1CjMnDkTe/fubTDmGAAqKyvr7H8rr4o0m80wm80trr82XXkxvABYjX6wOOmYMrnGltRqNpshSRKsViusVqtT67KHvBJWrkEUotYNsHY1iFo34PzarVYrJEmC2WxusHLeWX9vnZFLzeWCM2tVVFfAWF1uO7ZXEKChnFCTqHUD4tbOut2Lddv/XK3l6mxw9tdCbzoHAwCrd5Cmzh3UxLrdT9TaWbd7ubtuLeUC0HQ2OLPW+vQlubaM8AtnRtTC2tUhau2i1g2w9uaO21quzgannjeUn4Ox5p9mnQ9fR6pH5PpFrh1g/Wpj/Q2PdSE6ycGZwrGxsfjxxx/Rq1cvLF++HE888QR27dqFDz/8EEuXLsWff/7ZooKtViuuvvpqFBYW4vfffwcALF++HLfeemudUAGAfv36YejQoXjuuedw++2348SJE3XGAJtMJgQEBOD777/HmDFjGjzX/PnzsWDBggb3L1++vM6euq3RMfcnpJ3+BKdC+2N7h7udckxn8PLyQmxsLBISEtRbRU9EbUZVVRVOnjyJ7OxsVFdX13mfyWTClClTUFRUhODglq+Mc0YuuSMXavMxF2L0nvsgQYdvL34f0Omd/hxERCJqq9mQenoFknO/x+Go0djbbopTj01EJDIt5QLg/vMGAOia9SVSsr/Gscgr8VfCNJc8BxGRSNpiNvhV5WHk3tmw6IxYefG7TjkmEZEnsTcbHF4pXlRUpKzkXrVqFSZOnAh/f3+MGzcODz74YIsLvvvuu7Fnzx6lIe5Kjz76KGbPnq28XVxcjISEBIwcObJVQVqb/vf9wGkgvn1nxIwd65RjysxmM1avXo0RI0bAaDRe+ANqqaiowMmTJxEYGAhfX1+n1mUPSZJQUlKCoKAg6HQ6tz9/S4laN8Da1SBq3YDza6+oqICfnx8GDx7c4G9O7VUVreGMXGoqF4YOHYrNmze36O9ts87uB/YA8AvD2HFXOe+4NVqTE2oStW5A3NpZt3ux7gsTIRucec4g03+/BsgFOnTrhfaXa+fcQU2s2/1ErZ11u5e769ZSLgBNZwMAl31N9KvWA9lAYtd0tBvCjJCxdnWIWruodQOsvTGiZINTzxvO7gf2Anq/YIx1cq8BEPvnDBC7fpFrB1i/2lj/efZmg8NN8YSEBGzcuBHh4eFYtWoVVqxYAQA4d+5ci5us99xzD1auXIlff/0V7dq1U+6PjY1FVVUVCgsLERoaqtyfk5OD2NhY5TFbtmypc7ycnBzlfY3x8fGBj49Pg/uNRqPzfnAstrG4et9g6F30w9iSei0WC3Q6HfR6PfR6969MlMcxyzWIQtS6AdauBlHrBpxfu16vh06na/TvlbP+3jojl5rLBfnWqf9jYS4BAOj8wlz6PyxOr9tNRK0bELd21u1erLv553AGV2eD078OVaUAAIN/GAwaOnfQAtbtfqLWzrrdy111aykXgKazQa7VJV+TinMAAENQFDOiEaxdHaLWLmrdAGuvfzxncHU2OLfXUAEA0HkH8nWkZohcv8i1A6xfbazf/mxwuOPxwAMP4KabbkK7du0QHx+PIUOGAAB+/fVXpKWlOXQsSZJwzz334KuvvsLPP/+MDh061Hn/JZdcAqPRiLVr1yr3HThwAJmZmRg4cCAAYODAgdi9ezdyc3OVx6xevRrBwcFITU119NNznqoy261PoHo1EBG1Ac7MJbcpt72wBb8wdesgIvJQwmVDZc0VzT7OXYFOREQ2wuVCbaZ8261/hLp1EBF5GKGyocq2uAI+QerWQUQkOIdXit91113o168fTp48iREjRigrCTt27Iinn37aoWPdfffdWL58Ob755hsEBQUhOzsbABASEgI/Pz+EhIRg+vTpmD17NsLDwxEcHIx7770XAwcOxIABAwAAI0eORGpqKm6++WY8//zzyM7Oxty5c3H33Xc3efWuW8hNce8A9WogImoDnJlLblNeaLv1C1WzCiIijyVcNlQU2W592RQnInIF4XKhNlOB7dY/XN06iIg8jFDZUGmbLAXvtrMAz2K1YEfuDpw1nUWUfxR6R/eGQW9QuywiEpzdTfHLL78c11xzDa655hr06dMHffr0qfP+cePGOfzkb7zxBgAoV2HJ3n//fUybNg0A8NJLL0Gv12PixImorKzEqFGj8PrrryuPNRgMWLlyJWbOnImBAwciICAAU6dOxZNPPulwPU5VWXP1VhsKKiIid3JFLrlNG1opzpMYInInYbOhou2sFGcuEJE7CZsLtSlNca4UJyJyBiGzoWa7pbYylXbNiTVYtGURckw5yn0x/jF4pN8jGN5+uIqVEZHo7G6Kz5gxA9988w0WLFiAdu3a4eqrr8bVV1+NQYMGQafTtejJJUm64GN8fX3x73//G//+97+bfEz79u3x/ffft6gGl+FKcSIil3JFLrlNG2mK8ySGiNxN2GyQx6f7hqhbh4sxF4jI3YTNBZkktanx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TEc29EY2AMh0ZENvZAOATEc29EY2wHMMkCHuvvtuU1RU1Ovxbdu2GUnmzTffTD720ksvGUnmqaeeMrFYzMyYMcPMnj3bRKPRHh/71ltvGZ/PZ2699dZen/fCCy80S5YsGVBtp59+urnuuuv6/Pibb77ZjBkzxhQVFZmbbrrJhMNhc91115lRo0aZsWPHmt/85jfJj+ns7DSXX365qaioMDk5OWbChAnmu9/9bo/Pu3LlSnPOOeeY5557zkjq8Wf58uXGGGP27t1rvvCFL5ji4mKTl5dnFi9ebDZt2tTvsayvrzezZs0yn/vc50xHR4eJRqPmu9/9rpk0aZLJzc01Rx99tHn44YeTz3dee/Xq1WbWrFkmLy/PzJ071/zjH//oUesLL7xggsGgaW9vH9BxBIDBIBfiyAUA6EI2xJENANCFbIgjGwCgC9kQRzbAa5gUB/qQl5cnSQqFQnrrrbe0YcMGXXvttcrK6vkjc8wxx2jBggV64IEHPtLrvfjii5o9e3avx5999llVV1frL3/5i374wx9q+fLl+uxnP6tRo0bplVde0aWXXqovfelL2rlzpyTpjjvu0KOPPqqHHnpIGzdu1H333adJkyb1+JyPPvqolixZouOPP77XHW3O3Wxf/OIXtW7dOj366KNau3atjDH6zGc+o3A43KvGDz74QCeddJJmzpypP/zhD8rJydEtt9yi3/72t/r5z3+ud999V9dcc40uuOACvfDCCz0+9pvf/KZ+8IMfaN26dfL7/brooot6vH/27NmKRCJ65ZVXPsrhBYCPjFwgFwDgQGQD2QAAByIbyAYAOBDZQDbAIq625IEUGujdW42Njebzn/+8KSgoMLW1tebBBx/sdXdXd1dddZXJy8vr9fhA795qbGw0ksxf/vKXXh8/ceLEHneMTZ8+3Zx00knJtyORiBkxYoR54IEHjDHGXHnllWbevHkmFov1+Vo7d+40wWDQNDY2GmP6PiabNm0yksxLL72UfKyhocHk5eWZhx56qMfH/eMf/zDjx483V111VfI1Ozo6TH5+vvnb3/7W4/NefPHF5txzzzXG9Lx7y/H4448bSWb//v09Pm7UqFFm1apVfR88APgIyAVyAQAORDaQDQBwILKBbACAA5ENZAO8yZ+KxjvgBccff7yysrK0b98+HXbYYfr973+v8vLy5PuNMcPyuvv375ck5ebm9nrfUUcd1eOOsfLycs2cOTP5dnZ2tkpKSlRfXy8pftfVwoULNX36dC1evFif/exntWjRouTzH330UZ144okqLi7ut5733ntPfr9fc+bMST5WUlKi6dOn67333utR90knnaTzzjtPt99+e/LxLVu2qL29XQsXLuzxeUOhkD7+8Y/3eOzoo49O/r2yslKSVF9frwkTJiQfz8vLU3t7e7/1AsBwIRfiyAUA6EI2xJENANCFbIgjGwCgC9kQRzbANjTFgYTf//73mjFjhkpKSnr8Ip82bZqk+C/wA3/ROo87z/kwSkpK5PP51NjY2Ot9gUCgx9s+n6/Px2KxmCTp2GOP1bZt2/Tkk09q9erVOvvss7VgwQL94Q9/kBQPqn/913/90LV2l5OTowULFuj//u//9LWvfU1jx46VJLW1tUmSHn/88eRj3T+mv6/P5/NJUvJrcezdu1dlZWVDUjMADAa5MDjkAoBMQDYMDtkAIBOQDYNDNgDIBGTD4JANSBX2FAcSxo8fr8MPP7zXnU0f+9jHdMQRR+hHP/pRr1+ib7/9tlavXq1zzz33Q79uMBjUjBkztGHDhg/9OborLCzUOeeco1/+8pf6/e9/r//5n//R3r171dbWpueee05Llizp8drRaLTHxx955JG99tbYs2ePNm7cqBkzZiQfy8rK0u9+9zvNmjVLp5xyiqqrqyVJM2bMUE5Ojnbs2KEpU6b0+DN+/PhBfS1bt25VR0dHn/+DAADDjVyIIxcAoAvZEEc2AEAXsiGObACALmRDHNkA29AUBw7B5/Pp17/+tTZs2KClS5fq1Vdf1Y4dO/Twww/rjDPO0Ny5c3X11Vd/pNc49dRT9eKLL37kWn/4wx/qgQce0D/+8Q9t2rRJDz/8sCoqKlRcXKynnnpK06ZN06RJk5LPnzRpktra2rRmzRo1NDSovb1dU6dO1ZIlS3TJJZfoxRdf1Ntvv60LLrhAY8eO7RFyUnxJlfvuu0/HHHOM5s2bp9raWo0cOVLXXXedrrnmGt1zzz3aunWr3njjDf3kJz/RPffcM6iv569//asOO+wwHX744R/52ADAUCEXyAUAOBDZQDYAwIHIBrIBAA5ENpANcBdNcWAAjj/+eL388svKzs7WaaedpilTpuiGG27QhRdeqGeeeabXUh2DdfHFF+uJJ55Qc3PzR/o8I0eO1G233abZs2frE5/4hN5//3098cQTysrK0p/+9Kdey5kcf/zxuvTSS3XOOeeorKxMt912myTp7rvv1qxZs/TZz35Wc+fOlTFGTzzxRK/lVCTJ7/frgQce0FFHHaV58+apvr5e3/nOd7Rs2TLdcsstOvLII7V48WI9/vjjmjx58qC+ngceeECXXHLJhz8gADBMyAVyAQAORDaQDQBwILKBbACAA5ENZAPc4zPGGLeLACCdddZZOvbYY3XDDTcM+eeORCIqLy/Xk08+qeOOO27IP/9wePfddzVv3jxt2rRJRUVFbpcDAClHLvRELgAA2XAgsgEAyIYDkQ0AQDYciGyAg0lxwBLf//73VVBQMCyfe+/evbrmmmv0iU98Ylg+/3CoqanRb3/7W0IKQMYiF3oiFwCAbDgQ2QAAZMOByAYAIBsORDbAwaQ4AAAAAAAAAAAAACBtMSkOAAAAAAAAAAAAAEhbNMUBAAAAAAAAAAAAAGmLpjgAAAAAAAAAAAAAIG3RFAcAAAAAAAAAAAAApC2a4gAAAAAAAAAAAACAtEVTHAAAAAAAAAAAAACQtmiKAwAAAAAAAAAAAADSFk1xAAAAAAAAAAAAAEDaoikOAAAAAAAAAAAAAEhb/z8c3Pk+fvR86QAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a list to store the throughput and tpot data\n", + "throughput_tpot_data = []\n", + "\n", + "# Iterate over the models, batch sizes, and arrival rates to calculate throughput and tpot\n", + "for ssm in small_model_names:\n", + " for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/specinfer_llm_meta-llama-Llama-3.1-70B-Instruct_ssm_{model_name}_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " throughput = get_throughput(filepath)\n", + " tpot = get_tpot(filepath)\n", + " throughput_tpot_data.append({\n", + " 'Model': model_name,\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'Throughput': throughput,\n", + " 'TPOT': tpot\n", + " })\n", + "\n", + "# add incremental decoding entry\n", + "for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/incr_dec_llm_meta-llama-Llama-3.1-70B-Instruct_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " throughput = get_throughput(filepath)\n", + " tpot = get_tpot(filepath)\n", + " throughput_tpot_data.append({\n", + " 'Model': \"Incr Dec (baseline)\",\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'Throughput': throughput,\n", + " 'TPOT': tpot\n", + " })\n", + "\n", + "# Convert the list to a DataFrame\n", + "throughput_tpot_df = pd.DataFrame(throughput_tpot_data)\n", + "\n", + "# Plot the data\n", + "fig, axes = plt.subplots(nrows=1, ncols=len(arrival_rates), figsize=(20, 5), sharey=True)\n", + "\n", + "for i, arrival_rate in enumerate(arrival_rates):\n", + " ax = axes[i]\n", + " for model_name in throughput_tpot_df['Model'].unique():\n", + " model_data = throughput_tpot_df[(throughput_tpot_df['Model'] == model_name) & (throughput_tpot_df['Arrival Rate'] == arrival_rate)]\n", + " ax.plot(model_data['TPOT'], model_data['Throughput'], marker='o', label=model_name)\n", + " ax.set_title(f'Arrival Rate: {arrival_rate} {\"requests/sec\" if arrival_rate != \"offline\" else \"\"}')\n", + " ax.set_xlabel('TPOT (ms/token)')\n", + " ax.set_ylabel('Output Throughput (tokens/sec)')\n", + " ax.grid(True)\n", + " if i == 0:\n", + " ax.legend(title='Model')\n", + "\n", + "plt.suptitle('Throughput vs TPOT for Different Arrival Rates\\nLLM: LLAMA-3.1-70B-Instruct\\nBatch Sizes: 4, 8')\n", + "plt.tight_layout(rect=[0, 0, 1, 0.96])\n", + "\n", + "# Save the plot as a PDF\n", + "plt.savefig('/usr/FlexFlow/wildchat/throughput_vs_tpot.pdf')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n", + "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return ttft.mean()[1] / 1000\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Model Batch Size Arrival Rate TTFT\n", + "0 Zhuominc-Llama-3-330M 4 offline 236.037453\n", + "1 Zhuominc-Llama-3-330M 4 1 239.494513\n", + "2 Zhuominc-Llama-3-330M 4 2 236.035863\n", + "3 Zhuominc-Llama-3-330M 4 4 237.153932\n", + "4 Zhuominc-Llama-3-330M 4 8 237.309231\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABVwAAALvCAYAAACZeQ7oAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADqJ0lEQVR4nOzdeVyN6f8/8NeptC9atJFKoiSh7EP2KCR7tsq+CxmMqGQdu5mxLxlK9u0jS4OIjGXsNJgohpQ1khZ1//7o1/11nJZTIqbX8/s4j++c676W93Wfuz68Xee6JIIgCCAiIiIiIiIiIiKiz6ZQ1gEQERERERERERER/Vcw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKCROuRERERERERERERKWECVciIiIiIiIiIiKiUsKEKxEREREREREREVEpYcKViIiIiIiIiIiIqJQw4UpERCJvb29YWFh80TEkEgkCAwO/6BhlYeHChahWrRoUFRVRt27dsg5HRsuWLdGyZUupsqSkJPTo0QP6+vqQSCRYtmwZAODevXto3749dHR0IJFIsG/fvq8e739NfvdfXhYWFvD29i7VeL60z5lvWbOwsECnTp2++DiBgYGQSCRffBwiIiIi+vqYcCWib45EIinVV1RUFOLj4wu83rhxY/EvvkW9vpUEwo8//giJRILevXuXdShfxKefl4KCAvT09NCxY0ecO3euxP2uXLkSISEhpRfo/3fs2DH8+OOPaNasGTZt2oS5c+eW+hgf8/b2lro/mpqaqFatGnr06IHdu3cjJydHrn4mTJiAo0ePYtq0adiyZQs6dOgAAPDy8sKNGzcwZ84cbNmyBU5OTl9yOp9l7ty5cieEP36uZs+enW+dfv36ifeUvjwLCwupZ1lVVRXW1taYPHkyXr58WaI+Y2JiEBgYiNevX5dusHJKTU1FQEAAateuDQ0NDejr66Nu3boYP348njx5UiYxEREREdHXpVTWARARfWrLli1S73///XdERkbKlGdnZ0NRUbHIera2tnj//j0AwNPTE66urlLXK1WqBBMTE1SvXl0sS01NxciRI+Hh4YFu3bqJ5UZGRp83uVIgCAK2bdsGCwsLHDx4EG/fvoWWllap9L1u3Tq5k3VfQ97nlZ2djbt372LlypVo1aoV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V3DlyhUAuXumypNwffPmDQ4dOgQ3Nzepw7w+NWrUKFSoUAGLFy/GgQMHYGZmhqVLl+a7J21GRobUCmFtbW00aNAAW7ZsQZs2bYqM6XP0798fa9euxcqVK/H69WsYGxujd+/eCAwMhIJC7nb6xsbGWL16NebNm4fBgwcjOzsbJ0+eLDLZOXPmTDx79gy7du0SD+Y6fPiwTLvKlSvj/PnzmDFjBkJDQ/HmzRtUrlwZHTt2FP9BoaQxEBERERGRNIkgCEJZB0FERERERERERET0X6BQ1gEQERERERERERER/Vcw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKiVJZB/AtyMnJwZMnT6ClpQWJRFLW4RAREREREdF/nCAIePv2LUxNTaGgwLVQRET/JUy4Anjy5AnMzMzKOgwiIiIiIiIqZx49eoQqVaqUdRhERFSKmHAFoKWlBSD3f+i0tbXLOJryISsrC8eOHUP79u1RoUKFsg6H6Ivgc07lAZ9zKg/4nFN5wOf863vz5g3MzMzEv48SEdF/BxOugLiNgLa2NhOuX0lWVhbU1dWhra3NP9DRfxafcyoP+JxTecDnnMoDPudlh9vaERH993CjGCIiIiIiIiIiIqJSwoQrERERERERERERUSlhwpWIiIiIiIiIiIiolHAPVyIiIiIiIiIqVdnZ2cjKyirrMIiISo2ysjIUFORbu8qEKxERERERERGVCkEQ8PTpU7x+/bqsQyEiKlUKCgqwtLSEsrJykXWZcCUiIiIiIiKiUpGXbDU0NIS6ujokEklZh0RE9NlycnLw5MkTJCYmomrVqkX+bmPClYiIiIiIiIg+W3Z2tphs1dfXL+twiIhKVaVKlfDkyRN8+PABFSpUKLQuD80iIiIiIiIios+Wt2erurp6GUdCRFT68rYSyM7OLrIuE65EREREREREVGq4jQAR/RcV53cbE65EREREREREREREpYQJVyIiIiIiIiIiIqJSwoQrEREREREREVE5FBUVBYlEgtevX8vdxsLCAsuWLftiMRWkJLF+Td7e3ujatWup99uyZUv4+vqWer/0ZTHhSkRERERERET0jfH29oZEIsGIESNkro0ePRoSiQTe3t5fP7BvmIWFBSQSCSQSCRQVFWFqaorBgwfj1atXxernayU5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L8X3kf5vG4r169erTJkycnZ21ksvvaSoqCijzaZNm/Tss88qT548cnd3V1BQkE6fPq3Q0FCNGTNGBw8eNFbahoaGSpIsFotmz56tV155RXny5NGECROS3fLiu+++k8VisTr2ww8/qHr16sqVK5fy58+vFi1aSLr77+D06dMaMGCAcb+U2rFjh4KCgtS+fXv5+/urYcOGateu3QPfaXBwsMLDw234BpNH4AoAAAAAALK1rVu3qmrVqsmeGz16tGbNmqUdO3bozJkzeu211zRjxgyFhYVp9erV+vHHH61WHk6aNEmLFi3SnDlz9Mcff2jAgAHq2LGjNm/erMKFC+ubb76RJB09elRRUVFGiHjz5k0NHDhQe/bsUUREhOzs7NSiRQslJiamelw3btxQkyZNFBERof379+ull15ScHCwIiMjrdpNnz5dQUFB2r9/v5o2bapOnTqpc+fO6tixo/bt26fixYurc+fOxiPtt2/fVtWqVbV69WodOnRIPXr0UKdOnR4Ir9IiMTFRhQoV0vLly3X48GGNHDlS7733npYtW2bV7ueff9bZs2e1ZcsWTZs2TaNGjdLLL7+svHnzateuXXrrrbfUs2dP/f3338Y1Li4uCg0N1eHDhzVz5kzNmzdP06dPT3FtSUlJioiI0NGjR/X888+bNuZ7atWqpYiICP3555+SpIMHD2rbtm1q3LjxQ6+5fPmyli1bpho1ath8v5iYGE2ZMkWLFy/Wli1bFBkZqZCQEElSfHy8mjdvrjp16ui3337Tzp071aNHD1ksFrVp00bvvvuuypUrp6ioKEVFRalNmzZGv6NHj1aLFi30+++/6/XXX09RLatXr1aLFi3UpEkT7d+/XxEREXr22Wcl3d3WoVChQho7dqxxv5SqVauW9u7da8zREydOaM2aNWrSpIlVu2effVa//vqrYmNjU9x3cnKk6WoAAAAAAIBM7vTp0/L19U323Pjx4xUUFCRJ6t69u4YNG6bjx4+rWLFikqTWrVtr48aNGjJkiGJjYzVx4kT99NNPCgwMlCQVK1ZM27Zt02effaY6derIw8NDkuTl5WW12q9Vq1ZW9/3iiy/k6empw4cPq3z58qkaV8WKFa0eZR83bpxWrFihlStXqk+fPsbxJk2aqGfPnpKkkSNHavbs2apevbpeffVVSXdXhAYGBur8+fPy8fFRwYIFjUBO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Hcb2Ge+//7527dqlokWLPrK+PHnyWH22s7MztqW45/69c52cnB7ZX2rt3btXFy5cUJUqVYxjCQkJ2rJli2bNmmWsWJaky5cvGytp04LAFQAAAAAAZGuVK1fWl19+meZ+ypYtK0dHR0VGRqpOnTrJtsmZM6ckGasQpbsvoTp69KjmzZun5557TpIeeBlTakLL7du3q2vXrmrRooWku4HwqVOnbO4nuX6bNWumjh07SrobxP75558qW7aspLsrQe9fMZnae9SqVUu9evUyjqX1JWKStGPHDvn5+en99983jt3/CHmOHDmMEPNxEhMTFRsb+8g2X331lV5//XWFh4eradOmVufM+J7udy80vBfMp3Qcj2OxWBQUFKSgoCCNHDlSfn5+WrFihQYOHKicOXNazeVH8fT01Llz55SUlGSE+PeHwi4uLvL391dERITxcrl/c3BwSPH97qlfv75+//13q2PdunVT6dKlNWTIEON7k6RDhw6pcuXKNvWfHAJXAAAAAACQrTVq1EjDhg3TlStXkn17eUq5uLgoJCREAwYMUGJiomrXrq1r165p+/btcnV1VZcuXeTn5yeLxaJVq1apSZMmcnJyUt68eZUvXz7NnTtXBQoUUGRkpIYOHZrmcZUsWVLffvutgoODZbFYNGLEiDS9hOv+fr/++mvt2LFDefPm1bRp03T+/HkjcH2UixcvWoVs0t1H2JO7x6JFi7R+/XoVLVpUixcv1u7dux+7qjIltUdGRio8PFzVq1fX6tWrtWLFisdeN2nSJFWrVk3FixdXbGys1qxZo8WLF2v27NlGm2HDhumff/7RokWLJN3dRqBLly6aOXOmatSooXPnzkm6u5LTzc3tofe6fPmyIiMjdfbsWUl3X7AmST4+PlZ7l16/ft0IMM+cOaPBgwfL09PT6sVVabVr1y5FRESoYcOG8vLy0q5du3Tx4kWVKVNG0t3tCNavX6+jR48qX758jxxX3bp1dfHiRX3wwQdq3bq11q1bp7Vr11qtvh09erTeeusteXl5qXHjxrp+/bq2b9+ud955x7hfRESEgoKC5OjomKJfry4uLg/sg5wnTx7ly5fvgeNbt27VuHHjUvz9PAyBKwAAAAAASFdrK1TN6BIeKSAgQFWqVNGyZcuMl0el1rhx4+Tp6alJkybpxIkTcnd3V5UqVYyXOBUsWFBjxozR0KFD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WjXZc6NHj9asWbO0Y8cOnTlzRq+99ppmzJihsLAwrV69Wj/++KPVKrlJkyZp0aJFmjNnjv744w8NGDBAHTt21ObNm1W4cGFjj8ijR48qKirKCBFv3rypgQMHas+ePYqIiJCdnZ1atGihxMTEVI/rxo0batKkiSIiIrR//3699NJLCg4OVmRkpFW76dOnKygoSPv371fTpk3VqVMnde7cWR07dtS+fftUvHhxde7cWUlJSZKk27dvq2rVqlq9erUOHTqkHj16qFOnTlbhVVolJiaqUKFCWr58uQ4fPqyRI0fqvffe07Jly6za/fzzzzp79qy2bNmiadOmadSoUXr55ZeVN29e7dq1S2+99ZZ69uypv//+27jGxcVFoaGhOnz4sGbOnKl58+Zp+vTpKa4tKSlJEREROnr0qJ5//nmbxnT9+nV5eHik+JqU+ueff/TDDz+oRo0aNl97/Phxfffdd1q1apVWrVqlzZs3a/LkyZKkqKgotWvXTq+//rqOHDmiTZs2qWXLlkpKSlJISIhee+01vfTSS4qKilJUVJRq1apl9Dt06FD169dPR44ceew2CvfMnj1bvXv3Vo8ePfT7779r5cqVKlGihCRp9+7dkqQFCxYoKirK+JwStWrVUkREhP78809J0sGDB7Vt2zY1btzYqt2zzz6rrVu3prjfh2EPVwAAkGXYsj9cavd3AwAAWc/p06fl6+ub7Lnx48crKChIktS9e3cNGzZMx48fV7FixSRJrVu31saNGzVkyBDFxsZq4sSJ+umnnxQYGChJKlasmLZt26bPPvtMderUMcI2Ly8vqz1cW7VqZXXfL774Qp6enjp8+LDKly+fqnFVrFhRFStWND6PGzdOK1as0MqVK41Vg5LUpEkT9ezZU5I0cuRIzZ49W9WrV9err74q6e6K0MDAQJ0/f95YURkSEmJc/84772j9+vVatmyZnn322VTV+m8ODg4aM2aM8blo0aLauXOnli1bptdee8047uHhoY8++kh2dnYqVaqUPvjgA8XExOi9996TJA0bNkyTJ0/Wtm3b1LZtW0l39+q8x9/fXyEhIQoPD9fgwYMfWdO1a9dUsGBBxcbGyt7eXp9++qlefPHFFI9pypQpunHjhlX9aTFkyBANHz5cCQkJun37tmrUqKFp06bZ3E9iYqJCQ0Pl4uIi6e4K24iICE2YMEFRUVGK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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a list to store the TTFT data\n", + "ttft_data = []\n", + "\n", + "# Iterate over the models, batch sizes, and arrival rates to calculate TTFT\n", + "for ssm in small_model_names:\n", + " for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/specinfer_llm_meta-llama-Llama-3.1-70B-Instruct_ssm_{model_name}_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " ttft = get_ttft(filepath)\n", + " ttft_data.append({\n", + " 'Model': model_name,\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'TTFT': ttft\n", + " })\n", + "# add incremental decoding entry\n", + "for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/incr_dec_llm_meta-llama-Llama-3.1-70B-Instruct_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " ttft = get_ttft(filepath)\n", + " ttft_data.append({\n", + " 'Model': \"Incr Dec (baseline)\",\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'TTFT': ttft\n", + " })\n", + "\n", + "# Convert the list to a DataFrame\n", + "ttft_df = pd.DataFrame(ttft_data)\n", + "print(ttft_df.head())\n", + "\n", + "# Pivot the dataframe to have models and batch sizes as columns\n", + "pivot_df = ttft_df.pivot_table(index='Arrival Rate', columns=['Model', 'Batch Size'], values='TTFT')\n", + "\n", + "# Plot the data\n", + "fig, ax = plt.subplots(figsize=(12, 8))\n", + "\n", + "colors = ['lightgreen', 'skyblue', 'lightcoral', 'gold', 'plum', 'peachpuff', 'mediumturquoise', 'salmon']\n", + "pivot_df.plot(kind='bar', ax=ax, color=colors)\n", + "\n", + "ax.set_title('TTFT vs Arrival Rate for Different Models and Batch Sizes\\nLLM: LLAMA-3.1-70B-Instruct')\n", + "ax.set_xlabel('Arrival Rate')\n", + "ax.set_ylabel('TTFT (ms)')\n", + "ax.grid(True)\n", + "ax.legend(title='Model and Batch Size', bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "\n", + "# Save the plot as a PDF\n", + "plt.savefig('/usr/FlexFlow/wildchat/ttft_vs_arrival_rate.pdf')\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n", + "/tmp/ipykernel_3339078/2453520981.py:58: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + " queueing_time = group.apply(lambda x: x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -2][\"timestamp\"].values[0])\n", + "/tmp/ipykernel_3339078/2453520981.py:60: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " return queueing_time.mean()[1] / 1000000\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Model Batch Size Arrival Rate Queueing Time\n", + "0 Zhuominc-Llama-3-330M 4 offline 376.053818\n", + "1 Zhuominc-Llama-3-330M 4 1 319.585296\n", + "2 Zhuominc-Llama-3-330M 4 2 346.747481\n", + "3 Zhuominc-Llama-3-330M 4 4 360.138720\n", + "4 Zhuominc-Llama-3-330M 4 8 368.694877\n" + ] + }, + { + "data": { + "image/png": "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8WKdvLw8TJgwAQ8ePICSkhKsrKwwe/ZscXwBQK9evfDkyRNMmTIFycnJqFevHg4cOCCzkdb79PT0irwPvr6+iIuLw/Hjx4us9zEbN27E4MGDP6mN8kwivL+ISDmVlpYGbW1tpKamQktLq6zDKRdycnKwb98+uLi4yKyBQvShxS8WF6v+KJ1RnymS4uE4p+LgOKfygOOcygOOc5LXf/H30Ddv3uDBgwewtLQsdAOqr9nevXsxduxY3Lx584vPKiUqLa1atYKTkxNCQkJK3MatW7fQpk0b3Lt3D9ra2qUX3DeuON9xnOFKRERERET0DUh9byMTeWgHB3+mSIj+m1xdXXH//n0kJibCzMysrMMhKrbU1FTExsZi7969n9ROUlIS/vzzTyZbPwETrkREREREREREAAICAso6BKIS09bWxr///vvJ7bRr164UoinfOEeeiIiIiIiIiIiIqJQw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKCROuRERERERERERERKWECVciIiIiIiIiIiKiUsKEKxERERERERGVe8+ePYOhoSHi4uKKdV7r1q0REBDwWWL6VMePH4dEIsHLly/LLIawsDBUqlSpzPqn4jtw4ADq1auHvLy8sg7lm8WEKxERERERERF9XnckX+5VQjNmzIC7uzssLCwAvEukSiSSQl8nTpwopZvz+TRr1gxJSUnQ1tb+rP1IJBLs3Lnzs/bxuYSEhMDGxgbq6urQ0dFBu3btcO7cuSLPefbsGTp06AATExMoKyvDzMwM/v7+SEtLE+tER0ejefPm0NPTg6qqKmxsbLBw4UKZtpYuXQoLCwuoqKigcePGOH/+vNRxCwsLSCQSREREyJxbu3ZtSCQShIWFFeuaL1y4gLZt26JSpUrQ0dGBs7Mzrl27Jh7v0KEDKlSogPDw8GK1S/+jVNYBEBERERF9qtTQ0GLV1w4O/kyREBHRtygjIwOrVq3CwYMHxbLt27cjOztbql52djZcXV3F5NjXrmLFijAyMirrML5qNWrUwK+//opq1aohMzMTCxcuRPv27fH333/DwMCgwHMUFBTg7u6O6dOnw8DAAH///TeGDx+O58+fY8OGDQAAdXV1+Pv7o27dulBXV0d0dDSGDBkCdXV1+Pn5AQA2bdqEMWPGYMWKFWjcuDEWLVoEZ2dn3L17F4aGhmJ/ZmZmWLNmDTw9PcWys2fPIjk5Gerq6sW63vT0dHTo0AGdO3fGsmXL8PbtWwQHB8PZ2RkPHz5EhQoVAAC+vr5YsmQJ+vbtW6z26R3OcCUiIiIiIiKicm3fvn1QVlZGkyZNxDJdXV0YGRlJvaZNm4anT59ix44dUFFREevm5eXhp59+Es8JCQkRj8XFxUEikeDq1ati2cuXLyGRSHD8+HGx7MSJE2jUqBGUlZVhbGyM8ePH4+3bt+Lx1q1bY8SIEQgICICOjg4qV66MlStX4vXr1+jfvz80NTVRvXp17N+/XzznwyUF8h/vP3jwIGxtbaGhoYEOHTogKSlJ6n6sXr0atWvXFmPx9/f/xDv8P7GxsXB3d0flypWhoaGBhg0b4siRI1J1LCwsMH36dPTr1w8aGhowNzfH7t278eTJE7i7u0NDQwN169bFxYsXxXOePXsGLy8vmJqaQk1NDXZ2dti4ceNH4+nduzfatWuHatWqoXbt2liwYAHS0tJw/fr1Qs/R0dHBDz/8gAYNGsDc3Bxt27bFsGHDEBUVJdapX78+vLy8ULt2bVhYWKBPnz5wdnaWqrNgwQIMHjwY/fv3R61atbBixQqoqalh9erVUv15e3vjxIkTePjwoVi2evVqeHt7Q0mpeHMp79y5g+fPn2Pq1KmoWbMmateujeDgYDx+/Bjx8fFiPTc3N1y8eBGxsbHFap/eYcKViIiIiIiIiMq1qKgoODo6Flln2bJl+PPPP7Ft2zZUqVJF6tjatWuhrq6Oc+fOYc6cOZg6dSoOHz4sd/+JiYlwcXFBw4YNce3aNSxfvhyrVq3C9OnTZfrR19fH+fPnMWLECPzwww/o0aMHmjVrhsuXL6N9+/bo27cvMjIyCu0rIyMD8+bNw7p163Dy5EkkJCQgMDBQPL58+XIMHz4cfn5+uHHjBnbv3o3q1avLfS0fk56eDhcXF0RGRuLKlSvo0KED3NzckJCQIFVv4cKFaN68Oa5cuQJXV1f07dsX/fr1Q58+fXD58mVYWVmhX79+EAQBAPDmzRs4Ojpi7969uHnzJvz8/NC3b1+ZR/SLkp2djd9//x3a2tqwt7eX+7xHjx5h+/btaNWqVaF1rly5gtOnT4t1srOzcenSJbRr106so6CggHbt2uHMmTNS51auXBnOzs5Yu3YtgHc/w02bNmHAgAFyx5ivZs2a0NPTw6pVq5CdnY3MzEysWrUKtra24nIaAFC1alVUrlxZKkFM8mPClYiIiIiIiIjKtfj4eJiYmBR6/OTJkwgICMDSpUvRrFkzmeN169ZFcHAwrK2t0a9fPzRo0ACRkZFy979s2TKYmZnh119/hY2NDTw8PBAaGor58+dLbVxkb2+PoKAgWFtbY8KECVBRUYG+vj4GDx4Ma2trTJkyBc+ePStydmZOTg5WrFiBBg0awMHBAf7+/lKxTp8+HT/++CNGjRqFGjVqoGHDhqW6KZi9vT2GDBmCOnXqwNraGtOmTYOVlRV2794tVc/FxQVDhgwRrystLQ0NGzZEjx49UKNGDYwbNw4xMTF4/PgxAMDU1BSBgYGoV68eqlWrhhEjRqBDhw7YvHnzR2P666+/oKGhARUVFSxcuBCHDx+Gvr7+R8/z8vKCmpoaTE1NoaWlhT/++EOmTpUqVaCsrIwGDRpg+PDhGDRoEADg6dOnyM3NReXKlaXqV65cGcnJyTLtDBgwAGFhYRAEAVu3boWVlRXq1av30Rg/pKmpiePHj2P9+vVQVVWFhoYGDhw4gP3798vMljUxMZGa9UryY8KViIiIiIiIiMq1zMxMqSUC3peQkIDu3bvDz89PTJZ9qG7dulLvjY2NkZKSInf/MTExaNq0KSSS/2361bx5c6Snp+Pff/8tsB9FRUXo6enBzs5OLMtP3hXVt5qaGqysrAqMNSUlBY8ePULbtm0LPHfo0KHQ0NAQXyWRnp6OwMBA2NraolKlStDQ0EBMTIzMDNf3rzX/uoq61tzcXEybNg12dnbQ1dWFhoYGDh48KLYbHh4uFfv7MzednJxw9epVnD59Gh06dEDPnj3Fdjt27CieU7t2bakYFy5ciMuXL2PXrl2IjY3FmDFjZK43KioKFy9exIoVK7Bo0SK5ljkoiKurK9LT03Hy5EmsXr26RLNbgXdjfeDAgWjevDnOnj2LU6dOoU6dOnB1dUVmZqZUXVVV1SJnS1PhuGkWEREREREREZVr+vr6ePHihUx5ZmYmunTpgtq1a2PRokWFnp+/0VA+iUQizkxVUHg31y3/0Xfg3SzTkiion/fL8hO278+KlaeN/NhUVVWL7H/q1KlSyw+URGBgIA4fPox58+ahevXqUFVVRffu3WU2KCvouoq61rlz52Lx4sVYtGgR7OzsoK6ujoCAALHdzp07S210ZmpqKv63uro6qlevjurVq6NJkyawtrbGqlWrMGHCBPzxxx9iIvLDe5e/tq+NjQ10dXXRokULTJ48GcbGxmIdS0tLAO+SxY8fP0ZISAi8vLygr68PRUVFcYZuvsePHxe40ZmSkhL69u2L4OBgnDt3Djt27CjyPhdmw4YNiIuLw5kzZ8SxuWHDBujo6GDXrl1SG3M9f/680I3DqGhMuBIRERERERFRuVa/fn2sX79epnzQoEF4/vw5Dh48WOzNifLlJ6ySkpJQv359AJDaQAsAbG1tsW3bNgiCICYST506BU1NTZn1Yj8nTU1NWFhYIDIyEk5OTjLHDQ0NYWho+El9nDp1Cr6+vujSpQuAdzNe4+LiPqnN/Hbd3d3Rp08fAO8Ssffu3UOtWrUAvLs2TU1NudrKy8tDVlYWAOnE7MfOASCe97F2K1asCEdHR0RGRsLDw0M8HhkZWegmZQMGDMC8efPQq1cv6OjoyBXXhzIyMqCgoCA1mzr//fuJ+jdv3iA2NlYcs1Q8TLgSERERERERUbnm7OyMCRMm4MWLF2Iia+7cudiyZQv27NmDt2/fyqyrqa2t/dEZocC7WaNNmjTBrFmzYGlpiZSUFAQFBUnVGTZsGBYtWoQRI0bA398fd+/eRXBwMMaMGSPOQvxSQkJCMHToUBgaGqJjx4549eoVTp06hREjRhR53oMHD2QSydbW1jL1rK2tsX37dri5uUEikWDy5MlFzsiVl7W1NbZu3YrTp09DR0cHCxYswOPHj8WEa0Fev36NGTNmoHPnzjA2NsbTp0+xdOlSJCYmokePHoWet2/fPjx+/BgNGzaEhoYGbt26hbFjx6J58+bixlNLly5F1apVYWNjA+DdOsDz5s3DyJEjxXbGjBkDHx8fNGjQAI0aNcKiRYvw+vVr9O/fv8B+bW1t8fTpU6ipqZXgDr3z/fffY+zYsRg+fDhGjBiBvLw8zJo1C0pKSlJJ9rNnz0JZWRlNmzYtcV/lGROuRERERERERFSu2dnZwcHBAZs3b8aQIUMAvNvIKicnBx06dCjwnDVr1sDX11eu9levXo2BAwfC0dERNWvWxJw5c9C+fXvxuKmpKfbt24exY8fC3t4eurq6GDhwoExi9kvw8fHBmzdvsHDhQgQGBkJfXx/du3f/6HmFrV/6oQULFmDAgAFo1qwZ9PX1MW7cOKSlpX1y3EFBQfjnn3/g7OwMNTU1+Pn5wcPDA6mpqYWeo6ioiDt37mDt2rV4+vQp9PT00LBhQ0RFRcms1/o+VVVVrFy5EqNHj0ZWVhbMzMzQtWtXjB8/XqyTl5eHCRMm4MGDB1BSUoKVlRVmz54tji8A6NWrF548eYIpU6YgOTkZ9erVw4EDB2Q20nqfnp5ekffB19cXcXFxOH78eIHHbWxssGfPHoSGhqJp06ZQUFBA/fr1ceDAAamlEDZu3Ahvb+9PSu6WZxLh/UVEyqm0tDRoa2sjNTUVWlpaZR1OsSx+sbhY9UfpjPpMkRRPTk4O9u3bBxcXF5k1UIg+xHFO5QHHOZUHn3Ocp4aGFqtt7eBguetynFNxcJyTvL7l30ML8+bNGzx48ACWlpaFbkD1Ndu7dy/Gjh2LmzdvfvFZpUSlpVWrVnByckJISEiJ23j69Clq1qyJixcvimvQUvG+4zjDlYiIiIiIiIjKPVdXV9y/fx+JiYkwMzMr63CIii01NRWxsbHYu3fvJ7UTFxeHZcuWMdn6CZhwJSIiIiIiIiICEBAQUNYhEJWYtrY2/v33309up0GDBmjQoEEpRFR+MeFKRET0H/c5H0ElIiIiIiIiaVyUhIiIiIiIiIiIiKiUMOFKREREREREREREVEqYcCUiIiIiIiIiIiIqJUy4EhEREREREREREZUSJlyJiIiIiIiIiIiISgkTrkRERERERERERESlhAlXIiIiIiIiIir3nj17BkNDQ8TFxZV1KHI7fvw4JBIJXr58CQAICwtDpUqVyjSmkoqLi4NEIsHVq1fLOhQqp5o0aYJt27aVSltKpdIKEREREREREVEh/ln7zxfrq5pPtRKdN2PGDLi7u8PCwqJ0A/rA8ePH4eTkhBcvXnyzydGSat26NerVq4dFixaVdSjFtn37dsycORN///03cnJyYG1tjR9//BF9+/Yt9JykpCT8+OOPuHjxIv7++2+MHDlSrmvPzc1FSEgI1q9fj+TkZJiYmMDX1xdBQUGQSCQA3t3LEydOiOcYGhqiZcuWmDdvHszNzQttu7THX0hICHbu3PnFEuUWFhYICAhAQEBAiduIiIiAl5cX3N3dsXPnTrE8KCgIo0ePRpcuXaCg8GlzVDnDlYiIiIiIiIjKtYyMDKxatQoDBw4s61DoK6Wrq4tJkybhzJkzuH79Ovr374/+/fvj4MGDhZ6TlZUFAwMDBAUFwd7eXu6+Zs+ejeXLl+PXX39FTEwMZs+ejTlz5uCXX36Rqjd48GAkJSXh0aNH2LVrFx4+fIg+ffqU+Bo/p5ycnLIOAcC7mdSBgYFo0aKFzLGOHTvi1atX2L9//yf3U6YJ1+XLl6Nu3brQ0tKClpYWmjZtKnVRrVu3hkQikXoNHTpUqo2EhAS4urpCTU0NhoaGGDt2LN6+ffulL4WIiIiIiIiIvlH79u2DsrIymjRpIpblP65/8OBB1K9fH6qqqmjTpg1SUlKwf/9+2NraQktLC71790ZGRoZ4Xl5eHn7++WdYWlpCVVUV9vb22Lp1K4B3yR4nJycAgI6ODiQSCXx9fQEABw4cwHfffYdKlSpBT08PnTp1Qmxs7CddV2xsLNzd3VG5cmVoaGigYcOGOHLkiFQdCwsLTJ8+Hf369YOGhgbMzc2xe/duPHnyBO7u7tDQ0EDdunVx8eJF8Zxnz57By8sLpqamUFNTg52dHTZu3PhJsX4oNzcXAwcOFO9jzZo1sXjxYqk6vr6+8PDwwMyZM1G5cmVUqlQJU6dOxdu3bzF27Fjo6uqiSpUqWLNmjdR548aNQ40aNaCmpoZq1aph8uTJH00Itm7dGl26dIGtrS2srKwwatQo1K1bF9HR0YWeY2FhgcWLF6Nfv37Q1taW+9pPnz4Nd3d3uLq6wsLCAt27d0f79u1x/vx5qXpqamowMjKCsbExmjRpAn9/f1y+fFnufoD/LUNx8OBB2NraQkNDAx06dEBSUpJY5/jx42jUqBHU1dVRqVIlNG/eHPHx8QgLC0NoaCiuXbsm5u3CwsIAABKJBMuXL0fnzp2hrq6OGTNmFLjkxc6dO8VZu/n27NmDhg0bQkVFBfr6+ujSpQuAdz+D+Ph4jB49WuyvOHJzc+Ht7Y3Q0FBUqyY7E15RUREuLi6IiIgoVrsFKdOEa5UqVTBr1ixcunQJFy9eRJs2beDu7o5bt26JdfKz9fmvOXPmiMdyc3Ph6uqK7OxsnD59GmvXrkVYWBimTJlSFpdDRERERERERN+gqKgoODo6FngsJCQEv/76K06fPo2HDx+iZ8+eWLRoETZs2IC9e/fi0KFDUjMPf/75Z/z5559YsWIFbt26hdGjR6NPnz44ceIEzMzMxDUi7969i6SkJDGJ+Pr1a4wZMwYXL15EZGQkFBQU0KVLF+Tl5ZX4utLT0+Hi4oLIyEhcuXIFHTp0gJubGxISEqTqLVy4EM2bN8eVK1fg6uqKvn37ol+/fujTpw8uX74MKysr9OvXD4IgAADevHkDR0dH7N27Fzdv3oSfnx/69u0rkxD8FHl5eahSpQq2bNmC27dvY8qUKZg4cSI2b94sVe/o0aN49OgRTp48iQULFiA4OBidOnWCjo4Ozp07h6FDh2LIkCH4999/xXM0NTURFhaG27dvY/HixVi5ciUWLlwod2yCICAyMhJ3795Fy5YtS+2a8zVr1gyRkZG4d+8eAODatWuIjo5Gx44dCz3n+fPn2Lx5Mxo3blzs/jIyMjBv3jysW7cOJ0+eREJCAgIDAwEAb9++hYeHB1q1aoXr16/jzJkz8PPzg0QiQa9evfDjjz+idu3aYt6uV69eYrshISHo0qULbty4gQEDBsgVy969e9GlSxe4uLjgypUriIyMRKNGjQC8W9ahSpUqmDp1qthfcUydOhWGhoZFzmRv1KgRoqKiitVuQcp0DVc3Nzep9zNmzMDy5ctx9uxZ1K5dG8D/svUFOXToEG7fvo0jR46gcuXKqFevHqZNm4Zx48YhJCQEFStW/OzXQERERERERETftvj4eJiYmBR4bPr06WjevDkAYODAgZgwYQJiY2PFGXLdu3fHsWPHMG7cOGRlZWHmzJk4cuQImjZtCgCoVq0aoqOj8dtvv6FVq1bQ1dUF8G7Nzfdn+3Xr1k2q39WrV8PAwAC3b99GnTp1SnRd9vb2Uo+yT5s2DTt27MDu3bvh7+8vlru4uGDIkCEAgClTpmD58uVo2LAhevToAeDdjNCmTZvi8ePHMDIygqmpqZiQA4ARI0bg4MGD2Lx5s5gc+1QVKlRAaGio+N7S0hJnzpzB5s2b0bNnT7FcV1cXS5YsgYKCAmrWrIk5c+YgIyMDEydOBABMmDABs2bNQnR0NDw9PQG8W6szn4WFBQIDAxEREYGffvqpyJhSU1NhamqKrKwsKCoqYtmyZfj+++9L5XrfN378eKSlpcHGxgaKiorIzc3FjBkz4O3tLVVv2bJl+OOPPyAIAjIyMlCjRo0ilzgoTE5ODlasWAErKysAgL+/P6ZOnQoASEtLQ2pqKjp16iQet7W1Fc/V0NCAkpJSgbm73r17o3///sWKZcaMGfD09JT62eePYV1dXSgqKkJTU7PQXGFhoqOjsWrVqo+uNWtiYoKHDx8iLy/vk9Zx/Wo2zcrNzcWWLVvw+vVr8UsJAMLDw7F+/XoYGRnBzc0NkydPhpqaGgDgzJkzsLOzQ+XKlcX6zs7O+OGHH3Dr1i3Ur1+/wL6ysrKQlZUlvk9LSwPwboB9LWtKyEvytnjTp7+W68uP42uJh75uHOdUHnzOcf62mP9HoThtc5xTcXCcU3nAcU7y4r3+umRmZkJFRaXAY3Xr1hX/u3LlyuJj6O+X5c/s/Pvvv5GRkSGThMvOzi40R5Hv/v37mDJlCs6dO4enT5+KM1sTEhJQp04ddOzYUZx5Z25uLvV0cGHS09MREhKCvXv3IikpCW/fvkVmZqbMDNcPrxEA7OzsZMpSUlJgZGSE3NxczJw5E5s3b0ZiYiKys7ORlZUl5mvCw8PFBC4A7N+/v8A1Mz9m6dKlWL16NRISEpCZmYns7GzUq1dPqk7t2rWlEmOVK1eWSlArKipCT08PKSkpYtmmTZuwZMkSxMbGIj09HW/fvoWWlhaAd/e7Vq1aYt2JEyeKyVtNTU1cvXoV6enpiIyMxJgxY1CtWjW0bt262NcGvJtZ/f6s1d9++w3e3t7YvHkzwsPDsWHDBtSuXRtXr15FQEAATExM4OPjI9b39vbGpEmTAACPHz/GzJkz0b59e1y6dAmampqoXbs24uPjAQAtWrQodG1SNTU1MZkKAMbGxuL90tXVha+vL5ydnfH999+jXbt26NmzJ4yNjT96fQ0aNCj2Pbl69SoGDx5c7POK8urVK/Tt2xcrV66Evr5+kXVVVVWRl5eHrKwsqKqqlrjPMk+43rhxA02bNsWbN2+goaGBHTt2iAO7d+/eMDc3h4mJCa5fv45x48bh7t272L59OwAgOTlZKtkK/O9LIDk5udA+f/75Z6lMeb5Dhw6JXw7fCnMUvvNcQfZh32eKpGQOHz5c1iHQN4DjnMqDzzrO3/s/0PI1XvzPEMc5yYPjnMoDjnOS1/trflLZ09fXx4sXLwo8VqFCBfG/JRKJ1Pv8svzkaHp6OoB3j0WbmppK1VNWVi4yBjc3N5ibm2PlypUwMTFBXl4e6tSpg+zsbADAH3/8gczMTJmYihIYGIjDhw9j3rx5qF69OlRVVdG9e3exzcKusbCy/OucO3cuFi9ejEWLFsHOzg7q6uoICAgQ2+3cubPUo+0f3gt5REREIDAwEPPnz0fTpk2hqamJuXPn4ty5c4XGnh9rUT+jM2fOiOt4Ojs7Q1tbGxEREZg/fz6AdzMc358FmT8jGQAUFBRQvXp1AEC9evUQExODn3/+ucQJ1wYNGkj1lZ/TGjt2LMaPHy/OyLWzs0N8fDx+/vlnqYSrtra2GE/16tWxatUqGBsbY9OmTRg0aBD27dsn/nGnqORhQfcrf/kIAFizZg1GjhyJAwcOYNOmTQgKCsLhw4el1jwuiLq6utR7BQUFqXYB2T8+fUqSszCxsbGIi4uTetI+fzwoKSnh7t27YsL5+fPnUFdX/+Q4yjzhWrNmTVy9ehWpqanYunUrfHx8cOLECdSqVQt+fn5iPTs7OxgbG6Nt27aIjY2VyrwX14QJEzBmzBjxfVpaGszMzNC+fXvxLxrfiuUvlxer/g+VfvhMkRRPTk4ODh8+jO+//17ufyio/OI4p/Lgc47ztFmzitW21vjxctflOKfi4Din8oDjnOSV/6QlfR3q16+P9evXf3I7tWrVgrKyMhISEtCqVasC6+Qvf5ibmyuWPXv2DHfv3sXKlSvFmaAfbsZUkqTlqVOn4OvrK246lJ6ejri4uGK3U1C77u7u6NOnD4B3yat79+6JE+g0NTWhqan5yX00a9YMw4YNE8s+dRMx4N2GVObm5uLMUADiLFDgXQIuP4n5MfkzIUtKVVW1wL4yMjJkHmdXVFT86Hq+ioqKACAm5s3Ni/dHwKLUr18f9evXx4QJE9C0aVNs2LABTZo0QcWKFaXGclEMDAzw6tUrvH79WkzGfviIf926dREZGVnoUgTF6S+fjY0Nbty4IVUWFBSEV69eYfHixTAzMxPLb968+dHZ6PIo84RrxYoVxcHl6OiICxcu4P/Yu/f4nuv//+P392Zms/PsYA7bHHI+hTR8ipxCzh2cR4pChVYoh7EcUk4VisqQtVT0EZNYjpHkkERyXhj6hM0sM9t+f/ju/fO2mfd7e83MbtcuLhfv1+v5er4er9eeI/c9X8/X7Nmz9dFHH2Vpm/nTkSNHjqhixYry9/fPsiDzuXPnJCnHtRwcHR2z/cmSg4NDofufi4xiGXdudJN77foK4z3H3cc4R1GQn+O8mI0vWsjNeGWcwxqMcxQFjHNYi/t8b2nTpo1Gjx6tixcvytPTM9f9uLq6KiwsTMOHD1d6erqaNm2qhIQE/fjjj3Jzc1NoaKgCAwNlMpm0atUqtWvXTk5OTvL09JS3t7fmz5+v0qVLKy4uTqNs+KHJ7VSuXFnLly9Xhw4dZDKZNHbs2Dy9hOvmfr/66itt27ZNnp6emjFjhs6dO2fxKP7t/P3331lCtuweT69cubIWL16stWvXKjg4WEuWLNHOnTsVHByc59rj4uIUHR2thg0bavXq1VqxYsUdj5syZYoaNGigihUrKiUlRTExMVqyZInmzfv/P2gbPXq0Tp8+rcWLF5u3ZV5rUlKS+dqLFy+e473q0KGDJk2apPLly6tGjRras2ePZsyYkeXFU8nJyeYnvM+dO6eIiAiVKFFCrVu3tuWW5Oj48eOaP3++OnbsqICAAB06dEiHDx9W3759Jd1YA/f48ePau3evypYtK1dX19vO5m7UqJGcnZ31xhtv6OWXX9aOHTsUGRlp0Wb8+PFq0aKFKlasqO7du+v69euKiYnRyJEjzefbvHmzunfvLkdHxzsuESBJJUqUyLIOcub6ybdu37JliyH3r8AD11vl9NOBzEGa+Y0YEhKiSZMm6fz58/L19ZV04xEYNzc3q77JAQAAAABA/qsQWuHOjQpQrVq19OCDD2rZsmUWa4/mRkREhHx8fDRlyhQdO3ZMHh4eevDBB83rgJYpU0YTJkzQqFGj1L9/f/Xt21eRkZGKjo7Wyy+/rJo1a6pKlSp67733cv2oeqbMkK5x48YqVaqURo4cacjs6jFjxujYsWNq06aNnJ2dNXDgQHXu3FkJCQl3PDYqKkpRUVEW2yIiIsyzZTMNGjRIe/bs0TPPPCOTyaQePXpo8ODBt12H1FodO3bU8OHDNXToUKWkpKh9+/YaO3aswsPDczzuypUrGjx4sE6dOiUnJydVrVpVn332mZ555hlzm/j4+Czr4948W3LXrl2KiopSYGBgjjON33//fY0dO1aDBw/W+fPnFRAQoEGDBmncuHEW7RYsWKAFCxZIkjw9PVW7dm3FxMSoSpUqVt6NO3N2dtYff/yhRYsW6Z9//lHp0qU1ZMgQ8/dJt27dtHz5cjVv3lyXLl3SwoUL1a9fv2z78vLy0meffabXXntNCxYsUIsWLRQeHm7xhHuzZs305ZdfKiIiQlOnTpWbm5seeeQR8/6JEydq0KBB5uA7c4kCk8mU47mtcfr0aW3bts2Q2e6mjFsXT7iLRo8erbZt26p8+fK6fPmyoqKi9Pbbb2vt2rWqUKGCoqKi1K5dO3l7e2vfvn0aPny4ypYtq02bNkm6Mf2+bt26CggI0LRp03T27Fn16dNHzz33nCZPnmx1HYmJiXJ3d1dCQkKhW1Jg9sXZNrV/xfOVfKrENqmpqYqJiVG7du34yS7uiHGOoiA/x3lCNuuW58R9/Hir2zLOYQvGOYoCxjmsVZj/HXo7V69e1fHjxxUcHHzbF1Ddy1avXq3XXntN+/fvz9PbyQHcXcePH9cDDzygAwcOqHLlyrnuZ+TIkbp48aLmz5+f7X5b/owr0Bmu58+fV9++fRUfHy93d3fVrl1ba9euVatWrfTXX39p/fr1mjVrlq5cuaJy5cqpW7duGjNmjPl4e3t7rVq1Si+++KJCQkJUsmRJhYaGauLEiQV4VQAKk/z8hwsAAACAwqN9+/Y6fPiwTp8+bbGmI4B7W0xMjAYOHJinsFWSfH19Ld75lBcFGrh+8sknt91Xrlw580zWnAQGBiomF2/fBAAAAAAAuNmwYcMKugQANhoyZIgh/bz66quG9CNJzJEHAAAAAAAAAIMQuAIAAAAAAACAQQhcAQAAAAAAAMAgBK4AAAAAAAAAYBACVwAAAAAAAAAwCIErAAAAAAAAABiEwBUAAAAAAAAADELgCgAAAAAAirx//vlHvr6+OnHiREGXYrWNGzfKZDLp0qVLkqTIyEh5eHgUaE25deLECZlMJu3du7egS0ER1b17d02fPt2QvghcAQAAAABA/jr8/d37lUuTJk1Sp06dFBQUZNx1Z+PWkLQoadasmYYNG1bQZeTK8uXL1aBBA3l4eKhkyZKqW7eulixZkuMx8fHx6tmzpx544AHZ2dlZfe1paWkaO3asgoOD5eTkpIoVKyoiIkIZGRnmNs2aNZPJZDL/8vPz01NPPaWTJ0/m2LfR4y88PFx169Y1pC9rBAUFadasWbk6dtasWapSpYqcnJxUrlw5DR8+XFevXjXvHzNmjCZNmqSEhIQ810ngCgAAAAAAirTk5GR98sknGjBgQEGXgnuUl5eX3nzzTW3fvl379u1T//791b9/f61du/a2x6SkpMjHx0djxoxRnTp1rD7X22+/rXnz5umDDz7QwYMH9fbbb2vatGl6//33Ldo9//zzio+P15kzZ/Tf//5Xf/31l3r37p3ra8xPqampBXr+qKgojRo1SuPHj9fBgwf1ySef6IsvvtAbb7xhblOzZk1VrFhRn332WZ7PR+AKAAAAAACKtJiYGDk6Ourhhx82b8ucCbh27VrVq1dPTk5Oeuyxx3T+/HmtWbNG1apVk5ubm3r27Knk5GTzcenp6ZoyZYp5dmKdOnX01VdfSbrx2Hzz5s0lSZ6enjKZTOrXr58k6bvvvlPTpk3l4eEhb29vPfHEEzp69Gieruvo0aPq1KmT/Pz85OLiooYNG2r9+vUWbYKCgvTWW2+pb9++cnFxUWBgoFauXKm///5bnTp1kouLi2rXrq1ffvnFfMw///yjHj16qEyZMnJ2dlatWrX0+eef56nWW6WlpWnAgAHm+1ilShXNnj3bok2/fv3UuXNnTZ48WX5+fvLw8NDEiRN1/fp1vfbaa/Ly8lLZsmW1cOFCi+NGjhypBx54QM7OzqpQoYLGjh17x0CwWbNm6tKli6pVq6aKFSvqlVdeUe3atbV169bbHhMUFKTZs2erb9++cnd3t/rat23bpk6dOql9+/YKCgrSk08+qdatW+vnn3+2aOfs7Cx/f3+VLl1aDz/8sIYOHardu3dbfR7p/y9DsXbtWlWrVk0uLi56/PHHFR8fb26zceNGPfTQQypZsqQ8PDzUpEkTnTx5UpGRkZowYYJ+/fVX80zbyMhISZLJZNK8efPUsWNHlSxZUpMmTcp2yYtvvvlGJpPJYtu3336rhg0bqkSJEipVqpS6dOki6cbX4OTJkxo+fLj5fNbatm2bmjRpop49eyooKEitW7dWjx49stzTDh06KDo62oY7mD0CVwAAAAAAUKRt2bJF9evXz3ZfeHi4PvjgA23btk1//fWXnn76ac2aNUtRUVFavXq1vv/+e4uZh1OmTNHixYv14Ycf6vfff9fw4cPVu3dvbdq0SeXKldPXX38tSTp06JDi4+PNIeKVK1c0YsQI/fLLL4qNjZWdnZ26dOmi9PT0XF9XUlKS2rVrp9jYWO3Zs0ePP/64OnTooLi4OIt2M2fOVJMmTbRnzx61b99effr0Ud++fdW7d2/t3r1bFStWVN++fc2PtF+9elX169fX6tWrtX//fg0cOFB9+vTJEl7lRXp6usqWLasvv/xSBw4c0Lhx4/TGG29o2bJlFu1++OEHnTlzRps3b9aMGTM0fvx4PfHEE/L09NSOHTv0wgsvaNCgQTp16pT5GFdXV0VGRurAgQOaPXu2FixYoJkzZ1pdW0ZGhmJjY3Xo0CE98sgjhl1zpsaNGys2NlZ//vmnJOnXX3/V1q1b1bZt29sec+HCBS1btkyNGjWy+XzJycl69913tWTJEm3evFlxcXEKCwuTJF2/fl2dO3fWo48+qn379mn79u0aOHCgTCaTnnnmGb366quqUaOG4uPjFR8fr2eeecbcb3h4uLp06aLffvtNzz77rFW1rF69Wl26dFG7du20Z88excbG6qGHHpJ0Y1mHsmXLauLEiebzWatx48batWuXeYweO3ZMMTExateunUW7hx56SD///LNSUlKs7js7xfJ0NAAAAAAAQCF38uRJBQQEZLvvrbfeUpMmTSRJAwYM0OjRo3X06FFVqFBBkvTkk09qw4YNGjlypFJSUjR58mStX79eISEhkqQKFSpo69at+uijj/Too4/Ky8tLkuTr62sx269bt24W5/3000/l4+OjAwcOqGbNmrm6rjp16lg8yh4REaEVK1Zo5cqVGjp0qHl7u3btNGjQIEnSuHHjNG/ePDVs2FBPPfWUpBszQkNCQnTu3Dn5+/urTJky5kBOkl566SWtXbtWy5YtM4djeeXg4KAJEyaYPwcHB2v79u1atmyZnn76afN2Ly8vvffee7Kzs1OVKlU0bdo0JScnmx8VHz16tKZOnaqtW7eqe/fukm6s1ZkpKChIYWFhio6O1uuvv55jTQkJCSpTpoxSUlJkb2+vuXPnqlWrVoZc781GjRqlxMREVa1aVfb29kpLS9OkSZPUq1cvi3Zz587Vxx9/rIyMDCUnJ+uBBx7IcYmD20lNTdWHH36oihUrSpKGDh2qiRMnSpISExOVkJCgJ554wry/WrVq5mNdXFxUrFgx+fv7Z+m3Z8+e6t+/v021TJo0Sd27d7f42meOYS8vL9nb28vV1TXb8+WkZ8+e+t///qemTZsqIyND169f1wsvvGCxpIAkBQQE6Nq1azp79qwCAwNtOsfNmOEKAAAAAACKtH///VclSpTIdl/t2rXNv/fz8zM/hn7ztvPnz0uSjhw5ouTkZLVq1UouLi7mX4sXL77j8gCHDx9Wjx49VKFCBbm5uZlf3pU5G7Vt27bm/mrUqGHVdSUlJSksLEzVqlWTh4eHXFxcdPDgwSwzXG+9RkmqVatWlm2Z15mWlqaIiAjVqlVLXl5ecnFx0dq1a839Ll261OL6t2zZYlW9t5ozZ47q168vHx8fubi4aP78+Vlqr1Gjhuzs/n+85efnZ1G7vb29vL29zbVL0hdffKEmTZrI399fLi4uGjNmjLnfuLg4i9onT55sPs7V1VV79+7Vzp07NWnSJI0YMUIbN27M1bVJN2ZW33yupUuXSpKWLVumpUuXKioqSrt379aiRYv07rvvatGiRRbH9+rVS3v37jXPgK1UqZJat26ty5cvm+9NZt85zY51dnY2h6mSVLp0afP98vLyUr9+/dSmTRt16NBBs2fPtnpmaYMGDWy6H5K0d+9etWjRwubj7mTjxo2aPHmy5s6dq927d2v58uVavXq1IiIiLNo5OTlJksUyIbnBDFcAAAAAAFCklSpVShcvXsx2n4ODg/n3JpPJ4nPmtszH/pOSkiTdeCy6TJkyFu0cHR1zrKFDhw4KDAzUggULFBAQoPT0dNWsWVPXrl2TJH388cf6999/s9SUk7CwMK1bt07vvvuuKlWqJCcnJz355JPmPm93jbfblnmd77zzjmbPnq1Zs2apVq1aKlmypIYNG2but2PHjhaPtt96L6wRHR2tsLAwTZ8+XSEhIXJ1ddU777yjHTt23Lb2zFpz+hpt375dvXr10oQJE9SmTRu5u7srOjpa06dPl3RjhuPevXvNx2bOSJYkOzs7VapUSZJUt25dHTx4UFOmTFGzZs1svj7pRiB587kyg+3XXntNo0aNMs/IrVWrlk6ePKkpU6YoNDTU3N7d3d1cT6VKlfTJJ5+odOnS+uKLL/Tcc88pJibGvDZtZpCYnezuV+byEZK0cOFCvfzyy/ruu+/0xRdfaMyYMVq3bp3FmsfZKVmypMVnOzs7i36lrC/TyqnOvBg7dqz69Omj5557TtKNe3rlyhUNHDhQb775pjm0v3DhgiTJx8cnT+cjcAUAAAAAAEVavXr1DHkzefXq1eXo6Ki4uDg9+uij2bYpXry4pBuzRDP9888/OnTokBYsWKD//Oc/kpTlZUy5CS1//PFH9evXz/zSoaSkJJ04ccLmfrLrt1OnTurdu7ekG0Hsn3/+qerVq0u6MRPU1dU1z+do3LixBg8ebN6W15eISTdenhQYGKg333zTvO3kyZPm3xcrVswcYt5Jenp6ntb6dHJyyvZcycnJFrN2pRszde+0nq+9vb0kmYP5vDwSf6t69eqpXr16Gj16tEJCQhQVFaWHH35YxYsXtxjLOfHx8dHly5d15coVcxh7c+As3ZhtHRsbe9ulCGw5381ud08lWYTA+/fvV9myZVWqVCmbz3EzAlcAAAAAAFCktWnTRqNHj9bFixfl6emZ635cXV0VFham4cOHKz09XU2bNlVCQoJ+/PFHubm5KTQ0VIGBgTKZTFq1apXatWsnJycneXp6ytvbW/Pnz1fp0qUVFxenUaNG5fm6KleurOXLl6tDhw4ymUwaO3Zsnl7CdXO/X331lbZt2yZPT0/NmDFD586dMweuOfn777+zhGylS5fO9hyLFy/W2rVrFRwcrCVLlmjnzp0KDg7Oc+1xcXGKjo5Ww4YNtXr1aq1YseKOx02ZMkUNGjRQxYoVlZKSopiYGC1ZskTz5s0ztxk9erROnz6txYsXm7dlXmtSUpL52osXL57jverQoYMmTZqk8uXLq0aNGtqzZ49mzJiR5cVTycnJOnv2rCTp3LlzioiIUIkSJdS6dWtbbkmOjh8/rvnz56tjx44KCAjQoUOHdPjwYfXt21fSjTVwjx8/rr1796ps2bJydXW97WzuRo0aydnZWW+88YZefvll7dixQ5GRkRZtxo8frxYtWqhixYrq3r27rl+/rpiYGI0cOdJ8vs2bN6t79+5ydHS0Ohjt0KGDZsyYoXr16qlRo0Y6cuSIxo4dqw4dOpiDV+nGMg9G3D8CVwAAAAAAkL8qGxcA5YdatWrpwQcf1LJly8wvj8qtiIgI+fj4aMqUKTp27Jg8PDz04IMPml/OU6ZMGU2YMEGjRo1S//791bdvX0VGRio6Olovv/yyatasqSpVqui9997L9aPqmTJDusaNG6tUqVIaOXKkEhMT89SndOOlU8eOHVObNm3k7OysgQMHqnPnzkpISLjjsVFRUYqKirLYFhERYZ4tm2nQoEHas2ePnnnmGZlMJvXo0UODBw/WmjVr8lR7x44dNXz4cA0dOlQpKSlq3769xo4dq/Dw8ByPu3LligYPHqxTp07JyclJVatW1WeffaZnnnnG3CY+Pj7LGrP16tUz/37Xrl2KiopSYGBgjjON33//fY0dO1aDBw/W+fPnFRAQoEGDBmncuHEW7RYsWKAFCxZIkjw9PVW7dm3FxMSoSpUqVt6NO3N2dtYff/yhRYsW6Z9//lHp0qU1ZMgQ8/dJt27dtHz5cjVv3lyXLl3SwoUL1a9fv2z78vLy0meffabXXntNCxYsUIsWLRQeHq6BAwea2zRr1kxffvmlIiIiNHXqVLm5uemRRx4x7584caIGDRpkDr4zZ6eaTKYczz1mzBiZTCaNGTNGp0+flo+PjznYznT16lV98803+u677/J41yRTxq2LJxRBiYmJcnd3V0JCgtzc3Aq6HJvMvjjbpvaveL6ST5XYJjU1VTExMWrXrp3Va8+g6MrPcZ5w05sPreE+frzVbRnnsAXjHEUB4xxFAeMc1irM/w69natXr+r48eMKDg6+7Quo7mWrV6/Wa6+9pv3792d59BjAvev48eN64IEHdODAAVWuXDnX/cybN08rVqzQ999/n+1+W/6MY4YrAAAAAAAo8tq3b6/Dhw/r9OnTKleuXEGXA8BKMTExGjhwYJ7CVunGy8Pef/99Q2oicAUAAAAAAJA0bNiwgi4BgI2GDBliSD/PPfecIf1IEnPkAQAAAAAAAMAgBK4AAAAAAAAAYBACVwAAAAAAAAAwCIErAAAAAAAAABiEwBUAAAAAAAAADELgCgAAAAAAAAAGIXAFAAAAAAAAAIMQuAIAAAAAgCLvn3/+ka+vr06cOFHQpVht48aNMplMunTpkiQpMjJSHh4eBVpTbp04cUImk0l79+4t6FJQBF27dk1BQUH65ZdfDOmvmCG9AAAAAAAA3Ebbfbvu2rnW1K6fq+MmTZqkTp06KSgoyNiCbrFx40Y1b95cFy9eLLThaG41a9ZMdevW1axZswq6FJstX75ckydP1pEjR5SamqrKlSvr1VdfVZ8+fXI8Zt68edq7d69SUlJUo0YNhYeHq02bNnc814cffqhdu3bpwoUL2rNnj+rWrWvRJigoSCdPnpQk2dnZyc/PT23bttW7774rT0/P2/YdGRmpYcOGmUP6vOrXr58uXbqkb775xpD+7sRkMmnFihXq3LlzrvuYOnWqRo8erVdeecU8FosXL66wsDCNHDlSsbGxea6TGa4AAAAAAKBIS05O1ieffKIBAwYUdCm4R3l5eenNN9/U9u3btW/fPvXv31/9+/fX2rVrb3vM5s2b1apVK8XExGjXrl1q3ry5OnTooD179uR4ritXrqhp06Z6++23c2w3ceJExcfHKy4uTkuXLtXmzZv18ssv5+r68ltqampBlyBJ2rlzpz766CPVrl07y75evXpp69at+v333/N8HgJXAAAAAABQpMXExMjR0VEPP/yweVvm4/pr165VvXr15OTkpMcee0znz5/XmjVrVK1aNbm5ualnz55KTk42H5eenq4pU6YoODhYTk5OqlOnjr766itJNx6bb968uSTJ09NTJpNJ/fr1kyR99913atq0qTw8POTt7a0nnnhCR48ezdN1HT16VJ06dZKfn59cXFzUsGFDrV+/3qJNUFCQ3nrrLfXt21cuLi4KDAzUypUr9ffff6tTp05ycXFR7dq1LR61/ueff9SjRw+VKVNGzs7OqlWrlj7//PM81XqrtLQ0DRgwwHwfq1SpotmzZ1u06devnzp37qzJkyfLz89PHh4emjhxoq5fv67XXntNXl5eKlu2rBYuXGhx3MiRI/XAAw/I2dlZFSpU0NixY+8YCDZr1kxdunRRtWrVVLFiRb3yyiuqXbu2tm7dettjZs2apddff10NGzZU5cqVNXnyZFWuXFnffvttjufq06ePxo0bp5YtW+bYztXVVf7+/ipTpoyaN2+u0NBQ7d69O8djbhUeHq66detqyZIlCgoKkru7u7p3767Lly+b23z11VeqVauWnJyc5O3trZYtW+rKlSsKDw/XokWL9N///lcmk0kmk0kbN240Lw/xxRdf6NFHH1WJEiW0dOlS87luvUe3zir/9NNPVaNGDTk6Oqp06dIaOnSoJJnbdenSRSaTyebZ6ElJSerVq5cWLFiQ7SxgT09PNWnSRNHR0Tb1mx0CVwAAAAAAUKRt2bJF9etnvxRBeHi4PvjgA23btk1//fWXnn76ac2aNUtRUVFavXq1vv/+e73//vvm9lOmTNHixYv14Ycf6vfff9fw4cPVu3dvbdq0SeXKldPXX38tSTp06JDi4+PNIeKVK1c0YsQI/fLLL4qNjZWdnZ26dOmi9PT0XF9XUlKS2rVrp9jYWO3Zs0ePP/64OnTooLi4OIt2M2fOVJMmTbRnzx61b99effr0Ud++fdW7d2/t3r1bFStWVN++fZWRkSFJunr1qurXr6/Vq1dr//79GjhwoPr06aOff/4517XeKj09XWXLltWXX36pAwcOaNy4cXrjjTe0bNkyi3Y//PCDzpw5o82bN2vGjBkaP368nnjiCXl6emrHjh164YUXNGjQIJ06dcp8jKurqyIjI3XgwAHNnj1bCxYs0MyZM62uLSMjQ7Gx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PHjwjssoZJo3b56GDBmigQMH6rffftPKlStVqVIlSdLOnTslSQsXLlR8fLz5szUaN26s2NhY/fnnn5KkX3/9VVu3blXbtm0t2j300EPasmWL1f3eDmu4AgAAAACAIu3kyZMKCAjIdt9bb72lJk2aSJIGDBig0aNH6+jRo6pQoYIk6cknn9SGDRs0cuRIpaSkaPLkyVq/fr1CQkIkSRUqVNDWrVv10Ucf6dFHHzWHbb6+vhZruHbr1s3ivJ9++ql8fHx04MAB1axZM1fXVadOHdWpU8f8OSIiQitWrNDKlSvNswYlqV27dho0aJAkady4cZo3b54aNmyop556StKNGaEhISE6d+6ceUZlWFiY+fiXXnpJa9eu1bJly/TQQw/lqtZbOTg4aMKECebPwcHB2r59u5YtW6ann37avN3Ly0vvvfee7OzsVKVKFU2bNk3Jycl64403JEmjR4/W1KlTtXXrVnXv3l3SjbU6MwUFBSksLEzR0dF6/fXXc6wpISFBZcqUUUpKiuzt7TV37ly1atXK6mt69913lZSUZFF/XowcOVJjxoxRWlqarl69qkaNGmnGjBk295Oenq7IyEi5urpKujHDNjY2VpMmTVJ8fLyuX7+url27KjAwUJJUq1Yt87FOTk5KSUmRv79/ln6HDRumrl272lTLW2+9pVdffVWvvPKKeVvDhg0lST4+PpIkDw+PbM+Xk1GjRikxMVFVq1aVvb290tLSNGnSJPXq1cuiXUBAgP766y+lp6fnaR1XZrgCAAAAAIAi7d9//1WJEiWy3Ve7dm3z7/38/MyPod+87fz585KkI0eOKDk5Wa1atZKLi4v51+LFi++4PMDhw4fVo0cPVahQQW5ububHpTNno7Zt29bcX40aNay6rqSkJIWFhalatWry8PCQi4uLDh48mGWG663XKFmGapnbMq8zLS1NERERqlWrlry8vOTi4qK1a9ea+126dKnF9ed2xuCcOXNUv359+fj4yMXFRfPnz89Se40aNSyCMT8/P4va7e3t5e3tba5dkr744gs1adJE/v7+cnFx0ZgxY8z9xsXFWdQ+efJk83Gurq7au3evdu7cqUmTJmnEiBHauHGjVdcSFRWlCRMmaNmyZfL19ZWU9/v02muvae/evdq3b59iY2MlSe3bt1daWpokWfT9wgsv3LafoKAgc9gqSaVLlzbfrzp1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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a list to store the queueing time data\n", + "qt_data = []\n", + "\n", + "# Iterate over the models, batch sizes, and arrival rates to calculate queueing time\n", + "for ssm in small_model_names:\n", + " for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/specinfer_llm_meta-llama-Llama-3.1-70B-Instruct_ssm_{model_name}_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " qt = get_queueing_time(filepath)\n", + " qt_data.append({\n", + " 'Model': model_name,\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'Queueing Time': qt\n", + " })\n", + "# add incremental decoding entry\n", + "for batch_size in batch_sizes:\n", + " for arrival_rate in arrival_rates:\n", + " model_name = ssm.replace(\"/\", \"-\")\n", + " filepath = f\"/usr/FlexFlow/inference/output/incr_dec_llm_meta-llama-Llama-3.1-70B-Instruct_bz_{batch_size}_rate_{arrival_rate}_dataset_sharegpt.csv\"\n", + " if os.path.exists(filepath):\n", + " qt = get_queueing_time(filepath)\n", + " qt_data.append({\n", + " 'Model': \"Incr Dec (baseline)\",\n", + " 'Batch Size': batch_size,\n", + " 'Arrival Rate': arrival_rate,\n", + " 'Queueing Time': qt\n", + " })\n", + "\n", + "# Convert the list to a DataFrame\n", + "qt_df = pd.DataFrame(qt_data)\n", + "print(qt_df.head())\n", + "\n", + "# Pivot the dataframe to have models and batch sizes as columns\n", + "pivot_df = qt_df.pivot_table(index='Arrival Rate', columns=['Model', 'Batch Size'], values='Queueing Time')\n", + "\n", + "# Plot the data\n", + "fig, ax = plt.subplots(figsize=(12, 8))\n", + "\n", + "colors = ['lightgreen', 'skyblue', 'lightcoral', 'gold', 'plum', 'peachpuff', 'mediumturquoise', 'salmon']\n", + "pivot_df.plot(kind='bar', ax=ax, color=colors)\n", + "\n", + "ax.set_title('Queueing Time vs Arrival Rate for Different Models and Batch Sizes\\nLLM: LLAMA-3.1-70B-Instruct')\n", + "ax.set_xlabel('Arrival Rate')\n", + "ax.set_ylabel('Queueing Time (sec)')\n", + "ax.grid(True)\n", + "ax.legend(title='Model and Batch Size', bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "\n", + "# Save the plot as a PDF\n", + "plt.savefig('/usr/FlexFlow/wildchat/queueing_time_vs_arrival_rate.pdf')\n", + "\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/benchmarking/queueing_time_vs_arrival_rate.pdf b/benchmarking/queueing_time_vs_arrival_rate.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e77da10bad2cce12d587cb6ea92c4d3eada9af5d GIT binary patch literal 18042 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 Y3?Ms`$doA%iN)fTVG all_gpu_task_is; // Legion::FieldSpace field_space; + bool log_instance_creation; bool benchmarking, profiling, perform_fusion; bool inference_debugging; size_t simulator_work_space_size; diff --git a/include/flexflow/inference.h b/include/flexflow/inference.h index 4b1120887b..a866e52cbb 100644 --- a/include/flexflow/inference.h +++ b/include/flexflow/inference.h @@ -68,6 +68,7 @@ struct GenerationResult { std::vector output_tokens; double slo_ratio; double emission_time_ms; + int decoding_steps; }; // Contains the configuration for how to emit requests to the server, diff --git a/include/flexflow/model.h b/include/flexflow/model.h index 09a8dafc7e..825c8e9956 100644 --- a/include/flexflow/model.h +++ b/include/flexflow/model.h @@ -253,9 +253,7 @@ enum TaskIDs { RM_PREPARE_NEXT_BATCH_SPEC_TASK_ID, RM_PREPARE_NEXT_BATCH_VERIFY_TASK_ID, RM_BACKGROUND_SERVING_TASK_ID, - LOAD_FLOAT_WEIGHT_TASK_ID, - LOAD_HALF_WEIGHT_TASK_ID, - LOAD_QUANT_WEIGHT_TASK_ID, + LOAD_WEIGHT_TASK_ID, // Custom tasks CUSTOM_GPU_TASK_ID_FIRST, CUSTOM_GPU_TASK_ID_1, diff --git a/include/flexflow/ops/spec_inc_multihead_self_attention.h b/include/flexflow/ops/spec_inc_multihead_self_attention.h index 625cc9ee2b..e4e077e780 100644 --- a/include/flexflow/ops/spec_inc_multihead_self_attention.h +++ b/include/flexflow/ops/spec_inc_multihead_self_attention.h @@ -43,6 +43,7 @@ class SpecIncMultiHeadSelfAttention : public Op { bool _position_bias, bool allocate_weights, bool _streaming_cache, + int _tensor_parallelism_degree, char const *name); SpecIncMultiHeadSelfAttention(FFModel &model, ParallelTensor const _input, @@ -63,6 +64,7 @@ class SpecIncMultiHeadSelfAttention : public Op { bool _position_bias, bool allocate_weights, bool _streaming_cache, + int _tensor_parallelism_degree, char const *name); SpecIncMultiHeadSelfAttention(FFModel &model, SpecIncMultiHeadSelfAttention const &other, diff --git a/include/flexflow/ops/spec_inc_multihead_self_attention_params.h b/include/flexflow/ops/spec_inc_multihead_self_attention_params.h index 87f5098317..75cb576dc8 100644 --- a/include/flexflow/ops/spec_inc_multihead_self_attention_params.h +++ b/include/flexflow/ops/spec_inc_multihead_self_attention_params.h @@ -9,7 +9,8 @@ namespace FlexFlow { struct SpecIncMultiHeadSelfAttentionParams { LayerID layer_guid; - int embed_dim, num_q_heads, num_kv_heads, kdim, vdim; + int embed_dim, num_q_heads, num_kv_heads, kdim, vdim, + tensor_parallelism_degree; float dropout, scaling_factor; bool qkv_bias, final_bias, add_zero_attn, scaling_query, qk_prod_scaling, position_bias; diff --git a/include/flexflow/optimizer.h b/include/flexflow/optimizer.h index 4917df73c3..35f0c85429 100644 --- a/include/flexflow/optimizer.h +++ b/include/flexflow/optimizer.h @@ -61,8 +61,8 @@ class SGDOptimizer : public Optimizer { std::vector const ®ions, Legion::Context ctx, Legion::Runtime *runtime); - static void nccl_update_task_gpu(Context ctx, - Runtime *runtime, + static void nccl_update_task_gpu(Legion::Context ctx, + Legion::Runtime *runtime, SGDOptimizer const *op, OpMeta const *meta, float const *w_grad_ptr, @@ -106,8 +106,8 @@ class AdamOptimizer : public Optimizer { std::vector const ®ions, Legion::Context ctx, Legion::Runtime *runtime); - static void nccl_update_task_gpu(Context ctx, - Runtime *runtime, + static void nccl_update_task_gpu(Legion::Context ctx, + Legion::Runtime *runtime, AdamOptimizer const *op, OpMeta const *meta, float const *w_grad_ptr, diff --git a/include/flexflow/parallel_ops/kernels/allreduce_kernels.h b/include/flexflow/parallel_ops/kernels/allreduce_kernels.h index b8af8e8337..3436fc2a6e 100644 --- a/include/flexflow/parallel_ops/kernels/allreduce_kernels.h +++ b/include/flexflow/parallel_ops/kernels/allreduce_kernels.h @@ -31,15 +31,15 @@ class AllReduceMeta : public OpMeta { namespace Kernels { namespace AllReduce { -void inference_kernel_wrapper(Context ctx, - Runtime *runtime, +void inference_kernel_wrapper(Legion::Context ctx, + Legion::Runtime *runtime, AllReduceMeta *m, BatchConfig const *bc, GenericTensorAccessorR const &input, GenericTensorAccessorW const &output); -void forward_kernel_wrapper(Context ctx, - Runtime *runtime, +void forward_kernel_wrapper(Legion::Context ctx, + Legion::Runtime *runtime, AllReduceMeta const *m, GenericTensorAccessorR const &input, GenericTensorAccessorW const &output); diff --git a/include/flexflow/request_manager.h b/include/flexflow/request_manager.h index b76291129a..f86b234a06 100644 --- a/include/flexflow/request_manager.h +++ b/include/flexflow/request_manager.h @@ -148,7 +148,6 @@ struct Request { Status status = PENDING; std::vector tokens; - // TokenTree speculative_token_tree; std::vector speculative_token_trees; // To make request manager stateful, we need to store the causal mask here BatchConfig::BitMask causal_mask; @@ -231,6 +230,50 @@ struct Request { } }; +struct NewProfileInfo { + long long timestamp; + BatchConfig::RequestGuid request_guid; + int request_step_idx; + int num_speculated_tokens; + int num_accepted_tokens; + double speculation_score; + int num_generated_tokens; + long long speculation_start_timestamp; + long long speculation_end_timestamp; +}; +struct RequestProfileInfo { + int llm_prefilling_steps = 0; + int ssm_prefilling_steps = 0; + int llm_decoding_steps = 0; + int ssm_decoding_steps = 0; + long long start_time = 0, start_decoding_time = 0, finish_time = 0; + long long speculation_start_timestamp; + long long speculation_end_timestamp; + std::vector speculated_size_per_step; + std::vector accepted_tokens_per_step; + std::vector generated_tokens_per_step__; +}; +struct ProfileInfo { + // For SpecInfer: One step is comprised of one ssm speculation phase + a + // single llm verification phase (forward pass + verification) For Incr + // Decoding: One step is one LLM decoding phase + long long llm_step_start = 0, ssm_step_start = 0; + // Times for each LLM verification phase (in ms) + std::vector llm_step_times; + // Number of requests in batch at each step + std::vector requests_per_step; + // Times for each SSM speculation phase (in ms) + std::vector ssm_step_times; + // Number of requests getting decoded at each step + std::vector ssm_steps; + std::vector tree_operation_step_times; + // Number of generated tokens at each step + std::vector generated_tokens_per_step; + // To calculate the E2E time of serving + long long server_start_time = 0; + long long server_end_time = 0; +}; + class RequestManager { public: enum State { @@ -283,6 +326,8 @@ class RequestManager { void set_max_tree_depth(int max_tree_depth); int get_max_tree_width(); void set_max_tree_width(int max_tree_width); + int get_expansion_degree(); + void set_expansion_degree(int expansion_degree_); void set_speculative_sampling(bool speculative_sampling); void set_baseline_latency(double baseline_latency_ms); double get_baseline_latency(); @@ -309,7 +354,7 @@ class RequestManager { int register_ssm_model(FFModel *model); void register_tokenizer(ModelType model_type, int bos_token_id, - int eos_token_id, + std::vector eos_token_ids, std::string const &path); std::vector tokenize(std::string const &text); void register_output_filepath(std::string const &); @@ -329,6 +374,7 @@ class RequestManager { static void terminate_background_server_at_exit(); // Methods to check and mark request completion void trigger_request_completion_future(RequestGuid const &guid); + bool is_eos_token(TokenId token_id); static void background_serving_task( Legion::Task const *task, std::vector const ®ions, @@ -366,6 +412,12 @@ class RequestManager { int get_num_active_requests(); int get_empty_request_index(); + std::unordered_map get_requests_profiling(); + std::unordered_map + get_request_generation_results(); + ProfileInfo get_profiling_info(); + std::vector get_new_profiling_info(); + // Comparters struct SharedTokenTreeNodePtrRequestGuidWeightedLess { bool operator()( @@ -393,6 +445,7 @@ class RequestManager { int max_tree_depth; int max_tree_width; int k; + int expansion_degree = 3; // Profile based latency double baseline_latency_ms = 43; double ssm_spec_latency_ms = 17; @@ -416,9 +469,9 @@ class RequestManager { bool verbose; ModelType model_type; int bos_token_id; - int eos_token_id; + std::vector eos_token_ids; bool old_llama_tokenizer = false; - std::string output_filepath; + std::string output_filepath, csv_filepath; std::queue pending_request_queue; std::unordered_map all_requests; std::unordered_map request_generation_results; @@ -457,34 +510,9 @@ class RequestManager { // TODO: maintain this field size_t num_processed_requests; - struct RequestProfileInfo { - int llm_prefilling_steps = 0; - int ssm_prefilling_steps = 0; - int llm_decoding_steps = 0; - int ssm_decoding_steps = 0; - long long start_time = 0, start_decoding_time = 0, finish_time = 0; - }; - struct ProfileInfo { - // For SpecInfer: One step is comprised of one ssm speculation phase + a - // single llm verification phase (forward pass + verification) For Incr - // Decoding: One step is one LLM decoding phase - long long llm_step_start = 0, ssm_step_start = 0; - // Times for each LLM verification phase (in ms) - std::vector llm_step_times; - // Number of requests in batch at each step - std::vector requests_per_step; - // Times for each SSM speculation phase (in ms) - std::vector ssm_step_times; - // Number of requests getting decoded at each step - std::vector ssm_steps; - // Number of generated tokens at each step - std::vector generated_tokens_per_step; - // To calculate the E2E time of serving - long long server_start_time = 0; - }; - ProfileInfo profiling; std::unordered_map profiling_requests; + std::vector new_profiling_info; double total_request_run_time; bool load_pending_request_to_batch(); void request_update_attainment(int index, bool attained); diff --git a/include/flexflow/utils/communication_buffer.h b/include/flexflow/utils/communication_buffer.h index 3c14284d68..5935c48598 100644 --- a/include/flexflow/utils/communication_buffer.h +++ b/include/flexflow/utils/communication_buffer.h @@ -24,6 +24,7 @@ #include #endif #endif +#include "legion.h" // adapted from https://github.com/mlc-ai/relax @@ -58,7 +59,9 @@ class CommunicationBuffer { int *barrier_flag; }; -CommunicationBuffer *create_comm_buf_with_local_ptr(int num_devices, +CommunicationBuffer *create_comm_buf_with_local_ptr(Legion::Context ctx, + Legion::Runtime *runtime, + int num_devices, int device_id, ncclComm_t ncclComm, void *allgather_src, diff --git a/include/flexflow/utils/file_loader.h b/include/flexflow/utils/file_loader.h index a6771ee6a2..4ccc6db487 100644 --- a/include/flexflow/utils/file_loader.h +++ b/include/flexflow/utils/file_loader.h @@ -21,6 +21,7 @@ using namespace std; using namespace FlexFlow; +using namespace Legion; class FileDataLoader { public: @@ -36,29 +37,31 @@ class FileDataLoader { BatchConfig::TokenId *generate_requests(int num, int length); template - void load_single_weight_tensor(FFModel *ff, Layer *l, int weight_idx); + void load_single_weight_tensor(FFModel *ff, + Layer *l, + int weight_idx, + size_t volume, + size_t num_replicas, + DT *weight, + Domain weight_domain); - void load_quantization_weight(FFModel *ff, Layer *l, int weight_idx); -#ifdef DEADCODE - void load_weights(FFModel *ff); -#endif + void load_quantization_weight(FFModel *ff, + Layer *l, + int weight_idx, + size_t volume, + size_t num_replicas, + char *weight, + DataType data_type, + Domain weight_domain); static void - load_float_weight_task(Legion::Task const *task, - std::vector const ®ions, + load_weight_task(Legion::Task const *task, + std::vector const ®ions, + Legion::Context ctx, + Legion::Runtime *runtime); + void load_weights_parallel(FFModel *ff, Legion::Context ctx, Legion::Runtime *runtime); - static void - load_half_weight_task(Legion::Task const *task, - std::vector const ®ions, - Legion::Context ctx, - Legion::Runtime *runtime); - static void - load_quant_weight_task(Legion::Task const *task, - std::vector const ®ions, - Legion::Context ctx, - Legion::Runtime *runtime); - void load_weights_parallel(FFModel *ff, Context ctx, Runtime *runtime); void load_positions(FFModel *ff, Tensor pt, @@ -79,6 +82,15 @@ struct WeightLoadTaskArgs { FileDataLoader *loader; Layer *layer; int weight_idx; - WeightLoadTaskArgs(FFModel *_ff, FileDataLoader *_loader, Layer *_l, int _idx) - : ff(_ff), loader(_loader), layer(_l), weight_idx(_idx) {} + size_t volume, num_replicas; + DataType data_type; + WeightLoadTaskArgs(FFModel *_ff, + FileDataLoader *_loader, + Layer *_l, + int _idx, + size_t _volume, + size_t _num_replicas, + DataType _data_type) + : ff(_ff), loader(_loader), layer(_l), weight_idx(_idx), volume(_volume), + num_replicas(_num_replicas), data_type(_data_type) {} }; diff --git a/include/flexflow/utils/memory_allocator.h b/include/flexflow/utils/memory_allocator.h index 8e50a4c3b3..af3327b04d 100644 --- a/include/flexflow/utils/memory_allocator.h +++ b/include/flexflow/utils/memory_allocator.h @@ -23,7 +23,9 @@ namespace FlexFlow { class MemoryAllocator { public: MemoryAllocator(Legion::Memory memory); - void create_legion_instance(Realm::RegionInstance &inst, size_t size); + void create_legion_instance(Realm::RegionInstance &inst, + size_t size, + char const *task_name = NULL); void register_reserved_work_space(void *base, size_t size); inline void *allocate_reserved_untyped(size_t datalen) { void *ptr = static_cast(reserved_ptr) + reserved_allocated_size; @@ -60,6 +62,7 @@ class MemoryAllocator { void *instance_ptr; size_t reserved_total_size, reserved_allocated_size; size_t instance_total_size, instance_allocated_size; + bool log_instance_creation; }; }; // namespace FlexFlow diff --git a/inference/incr_decoding/incr_decoding.cc b/inference/incr_decoding/incr_decoding.cc index 2b2db8b952..959535e0d3 100644 --- a/inference/incr_decoding/incr_decoding.cc +++ b/inference/incr_decoding/incr_decoding.cc @@ -276,7 +276,8 @@ void FlexFlow::top_level_task(Task const *task, ModelType model_type = ModelType::UNKNOWN; auto architectures = model_config["architectures"]; for (auto const &str : architectures) { - if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM") { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { model_type = ModelType::LLAMA; break; } else if (str == "OPTForCausalLM") { @@ -296,9 +297,21 @@ void FlexFlow::top_level_task(Task const *task, int bos_token_id = model_config.find("bos_token_id") == model_config.end() ? -1 : (int)model_config.at("bos_token_id"); - int eos_token_id = model_config.find("eos_token_id") == model_config.end() - ? -1 - : (int)model_config.at("eos_token_id"); + // int eos_token_id = model_config.find("eos_token_id") == model_config.end() + // ? -1 + // : (int)model_config.at("eos_token_id"); + std::vector eos_token_ids; + if (model_config.find("eos_token_id") != model_config.end()) { + if (model_config["eos_token_id"].is_array()) { + for (auto &eos_token_id : model_config["eos_token_id"]) { + eos_token_ids.push_back(eos_token_id); + } + } else { + eos_token_ids.push_back(model_config["eos_token_id"]); + } + } else { + eos_token_ids.push_back(-1); + } assert(model_type != ModelType::UNKNOWN && "Invalid LLM model type passed (or no type was passed)."); @@ -322,7 +335,7 @@ void FlexFlow::top_level_task(Task const *task, rm->set_verbose(verbose); rm->set_streaming_cache(streaming_cache); rm->register_tokenizer( - model_type, bos_token_id, eos_token_id, tokenizer_filepath); + model_type, bos_token_id, eos_token_ids, tokenizer_filepath); rm->register_output_filepath(file_paths.output_file_path); FFModel model(ffconfig, ffconfig.cpu_offload); diff --git a/inference/simplified_infer/CMakeLists.txt b/inference/simplified_infer/CMakeLists.txt new file mode 100644 index 0000000000..35ee407114 --- /dev/null +++ b/inference/simplified_infer/CMakeLists.txt @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 3.10) + +project(FlexFlow_SpecInfer) +set(project_target1 specinfer) + + +set(CPU_SRC1 + ${FLEXFLOW_CPP_DRV_SRC} + specinfer.cc + ../models/llama.cc + ../models/opt.cc + ../models/falcon.cc + ../models/mpt.cc) + +if (FF_GPU_BACKEND STREQUAL "cuda" OR FF_GPU_BACKEND STREQUAL "hip_cuda") + cuda_add_executable(${project_target1} ${CPU_SRC1}) + if (FF_GPU_BACKEND STREQUAL "hip_cuda") + target_compile_definitions(${project_target1} PRIVATE __HIP_PLATFORM_NVIDIA__) + endif() +elseif(FF_GPU_BACKEND STREQUAL "hip_rocm") + set_source_files_properties(${CPU_SRC1} PROPERTIES LANGUAGE HIP) + hip_add_executable(${project_target1} ${CPU_SRC1}) + if (FF_HIP_ARCH STREQUAL "") + message(FATAL_ERROR "FF_HIP_ARCH is empty!") + endif() + set_property(TARGET ${project_target1} PROPERTY HIP_ARCHITECTURES "${FF_HIP_ARCH}") + target_compile_definitions(${project_target1} PRIVATE __HIP_PLATFORM_AMD__) +else() + message(FATAL_ERROR "Compilation of ${project_target1} for ${FF_GPU_BACKEND} backend not yet supported") +endif() + +target_include_directories(${project_target1} PRIVATE ${FLEXFLOW_INCLUDE_DIRS} ${CMAKE_INSTALL_INCLUDEDIR}) +target_include_directories(${project_target1} PRIVATE ${CMAKE_SOURCE_DIR}/inference) +target_link_libraries(${project_target1} -Wl,--whole-archive flexflow -Wl,--no-whole-archive ${FLEXFLOW_EXT_LIBRARIES}) + +set(BIN_DEST "bin") +install(TARGETS ${project_target1} DESTINATION ${BIN_DEST}) + + +project(FlexFlow_IncrDecoding) +set(project_target3 incr_dec) + + +set(CPU_SRC3 + ${FLEXFLOW_CPP_DRV_SRC} + incr_dec.cc + ../models/llama.cc + ../models/opt.cc + ../models/falcon.cc + ../models/mpt.cc) + +if (FF_GPU_BACKEND STREQUAL "cuda" OR FF_GPU_BACKEND STREQUAL "hip_cuda") + cuda_add_executable(${project_target3} ${CPU_SRC3}) + if (FF_GPU_BACKEND STREQUAL "hip_cuda") + target_compile_definitions(${project_target3} PRIVATE __HIP_PLATFORM_NVIDIA__) + endif() +elseif(FF_GPU_BACKEND STREQUAL "hip_rocm") + set_source_files_properties(${CPU_SRC3} PROPERTIES LANGUAGE HIP) + hip_add_executable(${project_target3} ${CPU_SRC3}) + if (FF_HIP_ARCH STREQUAL "") + message(FATAL_ERROR "FF_HIP_ARCH is empty!") + endif() + set_property(TARGET ${project_target3} PROPERTY HIP_ARCHITECTURES "${FF_HIP_ARCH}") + target_compile_definitions(${project_target3} PRIVATE __HIP_PLATFORM_AMD__) +else() + message(FATAL_ERROR "Compilation of ${project_target3} for ${FF_GPU_BACKEND} backend not yet supported") +endif() + +target_include_directories(${project_target3} PRIVATE ${FLEXFLOW_INCLUDE_DIRS} ${CMAKE_INSTALL_INCLUDEDIR}) +target_include_directories(${project_target3} PRIVATE ${CMAKE_SOURCE_DIR}/inference) +target_link_libraries(${project_target3} -Wl,--whole-archive flexflow -Wl,--no-whole-archive ${FLEXFLOW_EXT_LIBRARIES}) + +set(BIN_DEST "bin") +install(TARGETS ${project_target3} DESTINATION ${BIN_DEST}) diff --git a/inference/simplified_infer/incr_dec.cc b/inference/simplified_infer/incr_dec.cc new file mode 100644 index 0000000000..ed6125d0f8 --- /dev/null +++ b/inference/simplified_infer/incr_dec.cc @@ -0,0 +1,473 @@ +/* Copyright 2023 CMU, Facebook, LANL, MIT, NVIDIA, and Stanford (alphabetical) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flexflow/inference.h" +#include "flexflow/request_manager.h" +#include "models/falcon.h" +#include "models/llama.h" +#include "models/mpt.h" +#include "models/opt.h" +#include +#include + +using namespace FlexFlow; +using namespace Legion; +using json = nlohmann::json; + +Legion::Logger log_app("llama"); + +struct FilePaths { + std::string cache_folder_path; + std::string trace_file_path; + std::string trace_output_path; + std::string log_file_path; + std::string csv_file_path; +}; + +void parse_input_args(char **argv, + int argc, + FilePaths &paths, + std::string &llm_model_name, + bool &use_full_precision, + bool &verbose, + int &max_requests_per_batch, + int &max_tokens_per_batch, + int &max_sequence_length, + int &max_output_length, + bool &do_sample, + int &request_per_second, + bool &add_special_tokens, + std::string &target_partition) { + for (int i = 1; i < argc; i++) { + // llm model type + if (!strcmp(argv[i], "-llm-model")) { + llm_model_name = std::string(argv[++i]); + for (char &c : llm_model_name) { + c = std::tolower(c); + } + continue; + } + // cache folder + if (!strcmp(argv[i], "-cache-folder")) { + paths.cache_folder_path = std::string(argv[++i]); + continue; + } + // traces + if (!strcmp(argv[i], "-trace")) { + paths.trace_file_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-trace-output-path")) { + paths.trace_output_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-target-partition")) { + target_partition = std::string(argv[++i]); + continue; + } + // output file + if (!strcmp(argv[i], "-log-output-path")) { + paths.log_file_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-csv-output-path")) { + paths.csv_file_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--use-full-precision")) { + use_full_precision = true; + continue; + } + // verbose logging to stdout + if (!strcmp(argv[i], "--verbose")) { + verbose = true; + continue; + } + if (!strcmp(argv[i], "--do-sample")) { + do_sample = true; + continue; + } + if (!strcmp(argv[i], "--max-requests-per-batch")) { + max_requests_per_batch = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-tokens-per-batch")) { + max_tokens_per_batch = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-sequence-length")) { + max_sequence_length = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-output-length")) { + max_output_length = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--request-per-second")) { + request_per_second = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--add-special-tokens")) { + add_special_tokens = true; + continue; + } + } + if (paths.cache_folder_path.empty()) { + char const *ff_cache_path = std::getenv("FF_CACHE_PATH"); + paths.cache_folder_path = ff_cache_path ? std::string(ff_cache_path) + : std::string("~/.cache/flexflow"); + } + // Expand ~ to the home directory if needed + wordexp_t p; + wordexp(paths.cache_folder_path.c_str(), &p, 0); + paths.cache_folder_path = p.we_wordv[0]; + wordfree(&p); +} + +void FlexFlow::top_level_task(Task const *task, + std::vector const ®ions, + Context ctx, + Runtime *runtime) { + FFConfig ffconfig; + if (ffconfig.cpu_offload == false && ffconfig.quantization_type != DT_NONE) { + assert(false && "Doesn't support quantization in non-offload mode"); + } + FilePaths file_paths; + std::string llm_model_name; + bool use_full_precision = false; + bool verbose = false; + bool do_sample = false; + int max_requests_per_batch = 8; + int max_tokens_per_batch = 128; + int max_sequence_length = 512; + int max_output_length = 512; + int num_warmup_requests = 0; + double warmup_delay = 15.0; + RequestManager::DecodingMode decoding_mode = + RequestManager::INCREMENTAL_DECODING; + int sampling_seed = 0; + int request_per_second = -1; + bool add_special_tokens = false; + std::string target_partition = "FEATURE_EXTRACTION"; + + InputArgs const &command_args = HighLevelRuntime::get_input_args(); + char **argv = command_args.argv; + int argc = command_args.argc; + parse_input_args(argv, + argc, + file_paths, + llm_model_name, + use_full_precision, + verbose, + max_requests_per_batch, + max_tokens_per_batch, + max_sequence_length, + max_output_length, + do_sample, + request_per_second, + add_special_tokens, + target_partition); + + assert(ffconfig.data_parallelism_degree * ffconfig.tensor_parallelism_degree * + ffconfig.pipeline_parallelism_degree == + ffconfig.numNodes * ffconfig.workersPerNode); + + // Get dataset + std::ifstream input_file(file_paths.trace_file_path); + assert(input_file.good() && "Prompt file does not exist."); + nlohmann::ordered_json j = nlohmann::ordered_json::parse(input_file); + input_file.close(); + + // Find the partition with name "FEATURE_EXTRACTION" + auto &partitions = j["partitions"]; + auto it = + std::find_if(partitions.begin(), + partitions.end(), + [target_partition](nlohmann::ordered_json const &partition) { + return partition["partition_name"] == target_partition; + }); + nlohmann::ordered_json &partition = *it; + if (it == partitions.end()) { + std::cerr << "Partition " << target_partition + << " not found in the trace file." << std::endl; + assert(false); + } + // check that the max prompt + response length sum in the eval_entries in the + // partition does not exceed the max_sequence_length + int max_prompt_response_length = 0; + for (auto &eval_entry : partition["eval_entries"]) { + int prompt_length = eval_entry["prompt_length"]; + int response_length = eval_entry["response_length"]; + if (response_length >= max_output_length) { + std::cerr << "Error: A response length from the targt partition in the " + "dataset (=" + << response_length + << ") exceeds the max_output_length(=" << max_output_length + << ")." << std::endl; + assert(false); + } + max_prompt_response_length = + std::max(max_prompt_response_length, prompt_length + response_length); + } + if (max_prompt_response_length >= max_sequence_length) { + std::cerr << "Error: max prompt + response length sum (=" + << max_prompt_response_length + << ") in the eval_entries in the partition exceeds the " + "max_sequence_length(=" + << max_sequence_length << ")." << std::endl; + assert(false); + } + + // Get model configs + std::string config_filepath = join_path( + {file_paths.cache_folder_path, "configs", llm_model_name, "config.json"}); + std::string tokenizer_filepath = + join_path({file_paths.cache_folder_path, "tokenizers", llm_model_name}); + std::string weights_filepath = + join_path({file_paths.cache_folder_path, + "weights", + llm_model_name, + use_full_precision ? "full-precision" : "half-precision"}); + std::ifstream config_file_handle(config_filepath); + if (!config_file_handle.good()) { + std::cout << "Model config file " << config_filepath << " not found." + << std::endl; + assert(false); + } + json model_config = json::parse(config_file_handle, + /*parser_callback_t */ nullptr, + /*allow_exceptions */ true, + /*ignore_comments */ true); + ModelType model_type = ModelType::UNKNOWN; + auto architectures = model_config["architectures"]; + for (auto const &str : architectures) { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { + model_type = ModelType::LLAMA; + break; + } else if (str == "OPTForCausalLM") { + model_type = ModelType::OPT; + break; + } else if (str == "RWForCausalLM" || str == "FalconForCausalLM") { + model_type = ModelType::FALCON; + break; + } else if (str == "MPTForCausalLM") { + model_type = ModelType::MPT; + break; + } + } + int bos_token_id = model_config.find("bos_token_id") == model_config.end() + ? -1 + : (int)model_config.at("bos_token_id"); + std::vector eos_token_ids; + if (model_config.find("eos_token_id") != model_config.end()) { + if (model_config["eos_token_id"].is_array()) { + for (auto &eos_token_id : model_config["eos_token_id"]) { + eos_token_ids.push_back(eos_token_id); + } + } else { + eos_token_ids.push_back(model_config["eos_token_id"]); + } + } else { + eos_token_ids.push_back(-1); + } + + assert(model_type != ModelType::UNKNOWN && + "Invalid LLM model type passed (or no type was passed)."); + + // set request manager properties + srand(sampling_seed); + GenerationConfig generationConfig(do_sample, 0.8, 0.6, false, 16); + RequestManager *rm = RequestManager::get_request_manager(); + rm->set_max_requests_per_batch(max_requests_per_batch); + rm->set_max_tokens_per_batch(max_tokens_per_batch); + rm->set_max_tokens_per_ssm_batch(max_tokens_per_batch); + rm->set_max_tokens_per_prefilling_batch(max_tokens_per_batch); + rm->set_max_sequence_length(max_sequence_length); + rm->set_max_output_length(max_output_length); + rm->set_decoding_mode(decoding_mode); + rm->set_slo_violation_early_termination(false); + rm->set_baseline_latency(50); + rm->set_ssm_spec_latency(20); + rm->set_llm_verify_latency(50); + rm->set_spec_infer_old_version(true); + rm->set_greedy_schedule(false); + rm->set_equal_schedule(false); + rm->set_max_tree_depth(8); + rm->set_max_tree_width(16); + rm->set_verbose(verbose); + rm->set_streaming_cache(false); + rm->register_tokenizer( + model_type, bos_token_id, eos_token_ids, tokenizer_filepath); + rm->register_output_filepath(file_paths.log_file_path); + + FFModel model(ffconfig, ffconfig.cpu_offload); + if (model_type == ModelType::LLAMA) { + LLAMA::create_llama_model(model, + config_filepath, + weights_filepath, + INC_DECODING_MODE, + generationConfig, + false, + use_full_precision); + } else if (model_type == ModelType::OPT) { + OPT::create_opt_model(model, + config_filepath, + weights_filepath, + INC_DECODING_MODE, + use_full_precision); + } else if (model_type == ModelType::FALCON) { + FALCON::create_falcon_model(model, + config_filepath, + weights_filepath, + INC_DECODING_MODE, + use_full_precision); + } else if (model_type == ModelType::MPT) { + MPT::create_mpt_model(model, + config_filepath, + weights_filepath, + INC_DECODING_MODE, + generationConfig, + use_full_precision); + } else { + assert(false && "unknow model type"); + } + + rm->start_background_server(&model); + + int total_num_requests = 0; + { + // Iterate through eval_entries + std::vector requests; + std::vector timestamps, ratios; + if (partition.contains("num_warmup_requests")) { + num_warmup_requests = partition["num_warmup_requests"]; + } + for (auto &entry : partition["eval_entries"]) { + std::string text = entry["prompt"]; + int max_new_tokens_ = entry["response_length"]; + + bool is_warmup_request = total_num_requests < num_warmup_requests; + double request_delay = + 1000.0 * + (request_per_second > 0 ? (1.0 / (double)request_per_second) : 0); + double emission_time_ms = + is_warmup_request + ? 0.0 + : (warmup_delay + + request_delay * (total_num_requests - num_warmup_requests)); + + GenerationRequest inference_req(text, // prompt + -1.0, // slo_ratio + emission_time_ms, // emission_time_ms + add_special_tokens); + + requests.push_back(inference_req); + timestamps.push_back(emission_time_ms); + ratios.push_back(1.0); + total_num_requests++; + + if (verbose) { + break; + } + } + TraceEmissionMachine emission_machine(timestamps, ratios); + std::vector result = + model.generate(requests, emission_machine); + assert(result.size() == requests.size()); + assert(result.size() == total_num_requests); + assert(result.size() == partition["eval_entries"].size()); + int i = 0; + for (auto &entry : partition["eval_entries"]) { + entry["original_response"] = entry["response"]; + entry["original_response_length"] = entry["response_length"]; + std::string ff_out = result[i].output_text; + int tot_length = result[i].output_text.length(); + entry["response"] = ff_out; + entry["response_length"] = result[i].output_tokens.size(); + entry["specinfer_decoding_steps"] = result[i].decoding_steps; + i++; + } + + // Write the modified JSON to a file + std::ofstream output_file(file_paths.trace_output_path); + if (output_file.is_open()) { + output_file << j.dump(2); + output_file.close(); + std::cout << "Modified JSON has been saved to " + << file_paths.trace_output_path << std::endl; + } else { + std::cerr << "Unable to open file for writing." << std::endl; + } + } + + // terminate the request manager by stopping the background thread + rm->terminate_background_server(); + + std::string header = + "llm,partition,max_requests_per_batch,max_tokens_per_" + "batch,request_per_second,is_warmup_request,request_guid," + "request_step_idx,timestamp,num_generated_tokens"; + // csv filepath + // create csv filepath and add header if it doesn't exist + + bool csv_file_exists = std::filesystem::exists(file_paths.csv_file_path); + if (!csv_file_exists) { + // Create new file and write header + std::ofstream file(file_paths.csv_file_path); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << file_paths.csv_file_path + << std::endl; + assert(false); + } + file << header << "\n"; + file.close(); + } + + // Append the new row + std::ofstream file(file_paths.csv_file_path, std::ios::app); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << file_paths.csv_file_path + << std::endl; + } + + std::vector new_profiling_info = rm->get_new_profiling_info(); + for (auto const &info : new_profiling_info) { + file << llm_model_name + ","; + file << target_partition + ","; + file << std::to_string(max_requests_per_batch) + ","; + file << std::to_string(max_tokens_per_batch) + ","; + file << std::to_string(request_per_second) + ","; + bool is_warmup_request = + (info.request_guid - 1000000) < num_warmup_requests; + file << std::to_string(is_warmup_request) + ","; + file << info.request_guid << "," << info.request_step_idx << "," + << info.timestamp << "," << info.num_generated_tokens << "\n"; + } + file.close(); + + // Execution fence + { + Future future = runtime->issue_execution_fence(ctx); + future.get_void_result(); + } + + // float* data + std::cout << "----------inference finished--------------" << std::endl; + + // free tokenizer space in memory +} + +void FlexFlow::register_custom_tasks() {} diff --git a/inference/simplified_infer/specinfer.cc b/inference/simplified_infer/specinfer.cc new file mode 100644 index 0000000000..58f302075f --- /dev/null +++ b/inference/simplified_infer/specinfer.cc @@ -0,0 +1,692 @@ +/* Copyright 2023 CMU, Facebook, LANL, MIT, NVIDIA, and Stanford (alphabetical) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flexflow/inference.h" +#include "flexflow/request_manager.h" +#include "models/falcon.h" +#include "models/llama.h" +#include "models/mpt.h" +#include "models/opt.h" +#include +#include +#include +#include + +using namespace FlexFlow; +using namespace Legion; +using RequestGuid = BatchConfig::RequestGuid; + +Legion::Logger log_app("llama"); + +struct FilePaths { + std::string cache_folder_path; + std::string trace_file_path; + std::string trace_output_path; + std::string log_file_path; + std::string csv_file_path; +}; + +struct ModelNames { + std::string llm_model_name; + std::vector ssm_model_names; +}; + +struct ModelMeta { + ModelNames model_names; + + ModelType llm_model_type; + std::string llm_tokenizer_path; + std::string llm_weights_path; + std::string llm_model_config_path; + + int bos_token_id; + std::vector eos_token_ids; + + std::vector ssm_model_types; + std::vector ssm_model_config_paths; + std::vector ssm_model_weights_paths; +}; + +void parse_input_args(char **argv, + int argc, + FilePaths &paths, + ModelNames &model_names, + bool &use_full_precision, + bool &verbose, + int &ssm_tp_degree, + int &max_requests_per_batch, + int &max_tokens_per_batch, + int &max_sequence_length, + int &max_output_length, + int &max_tree_width, + int &max_tree_depth, + int &expansion_degree, + bool &do_sample, + int &request_per_second, + bool &add_special_tokens, + std::string &target_partition) { + for (int i = 1; i < argc; i++) { + // llm model name + if (!strcmp(argv[i], "-llm-model")) { + model_names.llm_model_name = std::string(argv[++i]); + for (char &c : model_names.llm_model_name) { + c = std::tolower(c); + } + continue; + } + // ssm models names + if (!strcmp(argv[i], "-ssm-model")) { + std::string ssm_model_name = std::string(argv[++i]); + for (char &c : ssm_model_name) { + c = std::tolower(c); + } + model_names.ssm_model_names.push_back(ssm_model_name); + continue; + } + if (!strcmp(argv[i], "-ssm-tp-degree")) { + ssm_tp_degree = std::stoi(argv[++i]); + continue; + } + // cache folder + if (!strcmp(argv[i], "-cache-folder")) { + paths.cache_folder_path = std::string(argv[++i]); + continue; + } + // trace + if (!strcmp(argv[i], "-trace")) { + paths.trace_file_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-trace-output-path")) { + paths.trace_output_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-target-partition")) { + target_partition = std::string(argv[++i]); + continue; + } + // output file + if (!strcmp(argv[i], "-log-output-path")) { + paths.log_file_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-csv-output-path")) { + paths.csv_file_path = std::string(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--use-full-precision")) { + use_full_precision = true; + continue; + } + // verbose logging to stdout + if (!strcmp(argv[i], "--verbose")) { + verbose = true; + continue; + } + if (!strcmp(argv[i], "--max-requests-per-batch")) { + max_requests_per_batch = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-tokens-per-batch")) { + max_tokens_per_batch = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-sequence-length")) { + max_sequence_length = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-output-length")) { + max_output_length = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-tree-width")) { + max_tree_width = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--max-tree-depth")) { + max_tree_depth = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--expansion-degree")) { + expansion_degree = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--do-sample")) { + do_sample = true; + continue; + } + if (!strcmp(argv[i], "--request-per-second")) { + request_per_second = std::stoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "--add-special-tokens")) { + add_special_tokens = true; + continue; + } + } + if (paths.cache_folder_path.empty()) { + char const *ff_cache_path = std::getenv("FF_CACHE_PATH"); + paths.cache_folder_path = ff_cache_path ? std::string(ff_cache_path) + : std::string("~/.cache/flexflow"); + } + // Expand ~ to the home directory if needed + wordexp_t p; + wordexp(paths.cache_folder_path.c_str(), &p, 0); + paths.cache_folder_path = p.we_wordv[0]; + wordfree(&p); +} + +void get_model_meta(FilePaths &file_paths, + ModelMeta &model_metadata, + bool use_full_precision) { + if (model_metadata.model_names.llm_model_name.empty() || + model_metadata.model_names.ssm_model_names.size() == 0) { + assert(false && "SpecInfer needs at least one LLM and one SSM for " + "speculative inference"); + } + model_metadata.llm_model_config_path = + join_path({file_paths.cache_folder_path, + "configs", + model_metadata.model_names.llm_model_name, + "config.json"}); + model_metadata.llm_tokenizer_path = + join_path({file_paths.cache_folder_path, + "tokenizers", + model_metadata.model_names.llm_model_name}); + model_metadata.llm_weights_path = + join_path({file_paths.cache_folder_path, + "weights", + model_metadata.model_names.llm_model_name, + use_full_precision ? "full-precision" : "half-precision"}); + + std::ifstream llm_config_file_handle(model_metadata.llm_model_config_path); + if (!llm_config_file_handle.good()) { + std::cout << "LLM Model config file " + << model_metadata.llm_model_config_path << " not found." + << std::endl; + assert(false); + } + nlohmann::ordered_json llm_model_config = + nlohmann::ordered_json::parse(llm_config_file_handle, + /*parser_callback_t */ nullptr, + /*allow_exceptions */ true, + /*ignore_comments */ true); + + model_metadata.llm_model_type = ModelType::UNKNOWN; + auto architectures = llm_model_config["architectures"]; + for (auto const &str : architectures) { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { + model_metadata.llm_model_type = ModelType::LLAMA; + break; + } else if (str == "OPTForCausalLM") { + model_metadata.llm_model_type = ModelType::OPT; + break; + } else if (str == "RWForCausalLM" || str == "FalconForCausalLM") { + model_metadata.llm_model_type = ModelType::FALCON; + break; + } else if (str == "MPTForCausalLM") { + model_metadata.llm_model_type = ModelType::MPT; + break; + } + } + model_metadata.bos_token_id = + llm_model_config.find("bos_token_id") == llm_model_config.end() + ? -1 + : (int)llm_model_config.at("bos_token_id"); + // model_metadata.eos_token_id = + // llm_model_config.find("eos_token_id") == llm_model_config.end() + // ? -1 + // : (int)llm_model_config.at("eos_token_id"); + if (llm_model_config.find("eos_token_id") != llm_model_config.end()) { + if (llm_model_config["eos_token_id"].is_array()) { + for (auto &eos_token_id : llm_model_config["eos_token_id"]) { + model_metadata.eos_token_ids.push_back(eos_token_id); + } + } else { + model_metadata.eos_token_ids.push_back(llm_model_config["eos_token_id"]); + } + } else { + model_metadata.eos_token_ids.push_back(-1); + } + + for (auto ssm_model_name : model_metadata.model_names.ssm_model_names) { + std::string ssm_config_path = join_path({file_paths.cache_folder_path, + "configs", + ssm_model_name, + "config.json"}); + std::string ssm_tokenizer_path = + join_path({file_paths.cache_folder_path, "tokenizers", ssm_model_name}); + std::string ssm_weights_path = + join_path({file_paths.cache_folder_path, + "weights", + ssm_model_name, + use_full_precision ? "full-precision" : "half-precision"}); + + std::ifstream ssm_config_file_handle(ssm_config_path); + if (!ssm_config_file_handle.good()) { + std::cout << "SSM Model config file " << ssm_config_path << " not found." + << std::endl; + assert(false); + } + nlohmann::ordered_json ssm_model_config = + nlohmann::ordered_json::parse(ssm_config_file_handle, + /*parser_callback_t */ nullptr, + /*allow_exceptions */ true, + /*ignore_comments */ true); + + ModelType ssm_model_type = ModelType::UNKNOWN; + auto architectures = ssm_model_config["architectures"]; + for (auto const &str : architectures) { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { + ssm_model_type = ModelType::LLAMA; + break; + } else if (str == "OPTForCausalLM") { + ssm_model_type = ModelType::OPT; + break; + } else if (str == "RWForCausalLM") { + ssm_model_type = ModelType::FALCON; + break; + } else if (str == "MPTForCausalLM") { + ssm_model_type = ModelType::MPT; + break; + } + } + int ssm_bos_id = + ssm_model_config.find("bos_token_id") == ssm_model_config.end() + ? -1 + : (int)ssm_model_config.at("bos_token_id"); + // int ssm_eos_id = + // ssm_model_config.find("eos_token_id") == ssm_model_config.end() + // ? -1 + // : (int)ssm_model_config.at("eos_token_id"); + // if (ssm_bos_id != model_metadata.bos_token_id || + // ssm_eos_id != model_metadata.eos_token_id) { + // printf("Warning: bos/eos token id mismatch between LLM and one of the " + // "SSMs!\n"); + // } + model_metadata.ssm_model_types.push_back(ssm_model_type); + model_metadata.ssm_model_config_paths.push_back(ssm_config_path); + model_metadata.ssm_model_weights_paths.push_back(ssm_weights_path); + } + + assert(model_metadata.llm_model_type != ModelType::UNKNOWN && + "Invalid LLM model type passed (or no type was passed)."); + + for (auto mt : model_metadata.ssm_model_types) { + if (mt == ModelType::UNKNOWN) { + assert(false && "One of the SSM model types passed is invalid."); + } + } +} + +void FlexFlow::top_level_task(Task const *task, + std::vector const ®ions, + Context ctx, + Runtime *runtime) { + FFConfig ffconfig; + FilePaths file_paths; + ModelMeta model_metadata; + bool use_full_precision = false; + bool verbose = false; + int ssm_tp_degree = 1; + int max_requests_per_batch = 8; + int max_tokens_per_batch = 128; + int max_sequence_length = 512; + int max_output_length = 512; + int expansion_degree = 3; + int max_tree_depth = 8; + int max_tree_width = 16; + RequestManager::DecodingMode decoding_mode = + RequestManager::SPECULATIVE_DECODING; + bool do_sample = false; + int sampling_seed = 0; + int request_per_second = -1; + int num_warmup_requests = 0; + double warmup_delay = 15.0; + bool add_special_tokens = false; + std::string target_partition = "FEATURE_EXTRACTION"; + + InputArgs const &command_args = HighLevelRuntime::get_input_args(); + char **argv = command_args.argv; + int argc = command_args.argc; + parse_input_args(argv, + argc, + file_paths, + model_metadata.model_names, + use_full_precision, + verbose, + ssm_tp_degree, + max_requests_per_batch, + max_tokens_per_batch, + max_sequence_length, + max_output_length, + max_tree_width, + max_tree_depth, + expansion_degree, + do_sample, + request_per_second, + add_special_tokens, + target_partition); + + get_model_meta(file_paths, model_metadata, use_full_precision); + + assert(ffconfig.data_parallelism_degree * ffconfig.tensor_parallelism_degree * + ffconfig.pipeline_parallelism_degree == + ffconfig.numNodes * ffconfig.workersPerNode); + assert(ssm_tp_degree >= 1 && + ssm_tp_degree <= ffconfig.numNodes * ffconfig.workersPerNode); + + std::ifstream input_file(file_paths.trace_file_path); + assert(input_file.good() && "Prompt file does not exist."); + nlohmann::ordered_json j = nlohmann::ordered_json::parse(input_file); + input_file.close(); + + // Find the partition with name "FEATURE_EXTRACTION" + auto &partitions = j["partitions"]; + auto it = + std::find_if(partitions.begin(), + partitions.end(), + [target_partition](nlohmann::ordered_json const &partition) { + return partition["partition_name"] == target_partition; + }); + nlohmann::ordered_json &partition = *it; + if (it == partitions.end()) { + std::cerr << "Partition " << target_partition + << " not found in the trace file." << std::endl; + assert(false); + } + // check that the max prompt + response length sum in the eval_entries in the + // partition does not exceed the max_sequence_length + int max_prompt_response_length = 0; + for (auto &eval_entry : partition["eval_entries"]) { + int prompt_length = eval_entry["prompt_length"]; + int response_length = eval_entry["response_length"]; + if (response_length >= max_output_length) { + std::cerr << "Error: A response length from the targt partition in the " + "dataset (=" + << response_length + << ") exceeds the max_output_length(=" << max_output_length + << ")." << std::endl; + assert(false); + } + max_prompt_response_length = + std::max(max_prompt_response_length, prompt_length + response_length); + } + if (max_prompt_response_length >= max_sequence_length) { + std::cerr << "Error: max prompt + response length sum (=" + << max_prompt_response_length + << ") in the eval_entries in the partition exceeds the " + "max_sequence_length(=" + << max_sequence_length << ")." << std::endl; + assert(false); + } + + // Sanity check for SpecInfer old version + assert(max_tree_depth <= 8); + assert(max_tree_width >= 3); + // Total verified tokens + assert(max_tokens_per_batch >= max_requests_per_batch * 21); + + // Create SentencePiece tokenizer or OPT tokenizer + srand(sampling_seed); + GenerationConfig generationConfig(do_sample, 0.8, 0.6, false, 16); + InferenceManager *im = InferenceManager::get_inference_manager(); + RequestManager *rm = RequestManager::get_request_manager(); + rm->set_max_requests_per_batch(max_requests_per_batch); + rm->set_max_tokens_per_batch(max_tokens_per_batch); + rm->set_max_tokens_per_ssm_batch(max_tokens_per_batch); + rm->set_max_tokens_per_prefilling_batch(max_tokens_per_batch); + rm->set_max_sequence_length(max_sequence_length); + rm->set_max_output_length(max_output_length); + rm->set_max_tree_depth(max_tree_depth); + rm->set_max_tree_width(max_tree_width); + rm->set_expansion_degree(expansion_degree); + rm->set_verbose(verbose); + rm->set_streaming_cache(false); + rm->register_tokenizer(model_metadata.llm_model_type, + model_metadata.bos_token_id, + model_metadata.eos_token_ids, + model_metadata.llm_tokenizer_path); + rm->set_decoding_mode(decoding_mode); + rm->set_slo_violation_early_termination(false); + rm->set_baseline_latency(50); + rm->set_ssm_spec_latency(20); + rm->set_llm_verify_latency(50); + rm->set_spec_infer_old_version(true); + rm->set_greedy_schedule(false); + rm->set_equal_schedule(false); + rm->register_output_filepath(file_paths.log_file_path); + + // Create LLM model + FFModel tree_model(ffconfig, ffconfig.cpu_offload); + if (model_metadata.llm_model_type == ModelType::LLAMA) { + LLAMA::create_llama_model(tree_model, + model_metadata.llm_model_config_path, + model_metadata.llm_weights_path, + TREE_VERIFY_MODE, + generationConfig, + false, + use_full_precision); + } else if (model_metadata.llm_model_type == ModelType::OPT) { + OPT::create_opt_model(tree_model, + model_metadata.llm_model_config_path, + model_metadata.llm_weights_path, + TREE_VERIFY_MODE, + use_full_precision); + } else if (model_metadata.llm_model_type == ModelType::FALCON) { + FALCON::create_falcon_model(tree_model, + model_metadata.llm_model_config_path, + model_metadata.llm_weights_path, + TREE_VERIFY_MODE, + use_full_precision); + } else if (model_metadata.llm_model_type == ModelType::MPT) { + MPT::create_mpt_model(tree_model, + model_metadata.llm_model_config_path, + model_metadata.llm_weights_path, + TREE_VERIFY_MODE, + generationConfig, + use_full_precision); + } else { + assert(false && "Invalid LLM model type passed (or no type was passed)."); + } + + // Create SSM models + int num_ssms = model_metadata.ssm_model_types.size(); + std::vector ssm_model_ids; + std::vector ssm_models; + FFConfig bm_config = ffconfig; + std::cout << "SSM TP Degree: " << ssm_tp_degree << std::endl; + // bm_config.data_parallelism_degree = bm_config.tensor_parallelism_degree = + // bm_config.pipeline_parallelism_degree = 1; + bm_config.data_parallelism_degree = 1; + bm_config.tensor_parallelism_degree = ssm_tp_degree; + bm_config.pipeline_parallelism_degree = 1; + for (int ssm_id = 0; ssm_id < num_ssms; ssm_id++) { + FFModel beam_model(bm_config); + ssm_models.push_back(beam_model); + } + + for (int ssm_id = 0; ssm_id < num_ssms; ssm_id++) { + FFModel &beam_model = ssm_models[ssm_id]; + if (model_metadata.ssm_model_types[ssm_id] == ModelType::LLAMA) { + LLAMA::create_llama_model(beam_model, + model_metadata.ssm_model_config_paths[ssm_id], + model_metadata.ssm_model_weights_paths[ssm_id], + TREE_SEARCH_MODE, + generationConfig, + false, + use_full_precision); + } else if (model_metadata.ssm_model_types[ssm_id] == ModelType::OPT) { + OPT::create_opt_model(beam_model, + model_metadata.ssm_model_config_paths[ssm_id], + model_metadata.ssm_model_weights_paths[ssm_id], + TREE_SEARCH_MODE, + use_full_precision); + } else if (model_metadata.ssm_model_types[ssm_id] == ModelType::FALCON) { + FALCON::create_falcon_model( + beam_model, + model_metadata.ssm_model_config_paths[ssm_id], + model_metadata.ssm_model_weights_paths[ssm_id], + TREE_SEARCH_MODE, + use_full_precision); + } else if (model_metadata.ssm_model_types[ssm_id] == ModelType::MPT) { + MPT::create_mpt_model(beam_model, + model_metadata.ssm_model_config_paths[ssm_id], + model_metadata.ssm_model_weights_paths[ssm_id], + TREE_SEARCH_MODE, + generationConfig, + use_full_precision); + } else { + assert(false && "Invalid SSM model type passed."); + } + + rm->register_ssm_model(&beam_model); + } + + rm->start_background_server(&tree_model); + + int total_num_requests = 0; + { + // Iterate through eval_entries + std::vector requests; + std::vector timestamps, ratios; + if (partition.contains("num_warmup_requests")) { + num_warmup_requests = partition["num_warmup_requests"]; + } + for (auto &entry : partition["eval_entries"]) { + std::string text = entry["prompt"]; + int max_new_tokens_ = entry["response_length"]; + + bool is_warmup_request = total_num_requests < num_warmup_requests; + double request_delay = + 1000.0 * + (request_per_second > 0 ? (1.0 / (double)request_per_second) : 0); + double emission_time_ms = + is_warmup_request + ? 0.0 + : (warmup_delay + + request_delay * (total_num_requests - num_warmup_requests)); + + GenerationRequest inference_req(text, // prompt + -1.0, // slo_ratio + emission_time_ms, // emission_time_ms + add_special_tokens); + requests.push_back(inference_req); + timestamps.push_back(emission_time_ms); + ratios.push_back(1.0); + total_num_requests++; + + if (verbose) { + break; + } + } + TraceEmissionMachine emission_machine(timestamps, ratios); + std::vector result = + tree_model.generate(requests, emission_machine); + assert(result.size() == requests.size()); + assert(result.size() == total_num_requests); + assert(result.size() == partition["eval_entries"].size()); + int i = 0; + for (auto &entry : partition["eval_entries"]) { + entry["original_response"] = entry["response"]; + entry["original_response_length"] = entry["response_length"]; + std::string ff_out = result[i].output_text; + int tot_length = result[i].output_text.length(); + entry["response"] = ff_out; + entry["response_length"] = result[i].output_tokens.size(); + entry["specinfer_decoding_steps"] = result[i].decoding_steps; + i++; + } + + // Write the modified JSON to a file + std::ofstream output_file(file_paths.trace_output_path); + if (output_file.is_open()) { + output_file << j.dump(2); + output_file.close(); + std::cout << "Modified JSON has been saved to " + << file_paths.trace_output_path << std::endl; + } else { + std::cerr << "Unable to open file for writing." << std::endl; + } + } + + // terminate the request manager by stopping the background thread + rm->terminate_background_server(); + + std::string header = + "llm,ssm,partition,expansion_degree,max_tree_depth,max_tree_width,max_" + "requests_per_batch,max_tokens_per_batch,request_per_second,is_warmup_" + "request,request_guid," + "request_step_idx," + "timestamp,speculation_start_timestamp,speculation_end_timestamp,num_" + "speculated_tokens,num_accepted_tokens,num_generated_tokens"; + // csv filepath + // create csv filepath and add header if it doesn't exist + + bool csv_file_exists = std::filesystem::exists(file_paths.csv_file_path); + if (!csv_file_exists) { + // Create new file and write header + std::ofstream file(file_paths.csv_file_path); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << file_paths.csv_file_path + << std::endl; + assert(false); + } + file << header << "\n"; + file.close(); + } + + // Append the new row + std::ofstream file(file_paths.csv_file_path, std::ios::app); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << file_paths.csv_file_path + << std::endl; + } + + std::vector new_profiling_info = rm->get_new_profiling_info(); + for (auto const &info : new_profiling_info) { + file << model_metadata.model_names.llm_model_name + ","; + file << model_metadata.model_names.ssm_model_names[0] + ","; + file << target_partition + ","; + file << std::to_string(expansion_degree) + ","; + file << std::to_string(max_tree_depth) + ","; + file << std::to_string(max_tree_width) + ","; + file << std::to_string(max_requests_per_batch) + ","; + file << std::to_string(max_tokens_per_batch) + ","; + file << std::to_string(request_per_second) + ","; + bool is_warmup_request = + (info.request_guid - 1000000) < num_warmup_requests; + file << std::to_string(is_warmup_request) + ","; + file << info.request_guid << "," << info.request_step_idx << "," + << info.timestamp << "," << info.speculation_start_timestamp << "," + << info.speculation_end_timestamp << "," << info.num_speculated_tokens + << "," << info.num_accepted_tokens << "," << info.num_generated_tokens + << "\n"; + } + file.close(); + + // Execution fence + { + Future future = runtime->issue_execution_fence(ctx); + future.get_void_result(); + } + + // float* data + std::cout << "----------inference finished--------------" << std::endl; +} + +void FlexFlow::register_custom_tasks() {} diff --git a/inference/spec_infer/spec_infer.cc b/inference/spec_infer/spec_infer.cc index cde24f7b27..6be63c7fbb 100644 --- a/inference/spec_infer/spec_infer.cc +++ b/inference/spec_infer/spec_infer.cc @@ -49,7 +49,8 @@ struct ModelMeta { std::string llm_weights_path; std::string llm_model_config_path; - int bos_token_id, eos_token_id; + int bos_token_id; + std::vector eos_token_ids; std::vector ssm_model_types; std::vector ssm_model_config_paths; @@ -276,7 +277,8 @@ void get_model_meta(FilePaths &file_paths, model_metadata.llm_model_type = ModelType::UNKNOWN; auto architectures = llm_model_config["architectures"]; for (auto const &str : architectures) { - if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM") { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { model_metadata.llm_model_type = ModelType::LLAMA; break; } else if (str == "OPTForCausalLM") { @@ -294,10 +296,21 @@ void get_model_meta(FilePaths &file_paths, llm_model_config.find("bos_token_id") == llm_model_config.end() ? -1 : (int)llm_model_config.at("bos_token_id"); - model_metadata.eos_token_id = - llm_model_config.find("eos_token_id") == llm_model_config.end() - ? -1 - : (int)llm_model_config.at("eos_token_id"); + // model_metadata.eos_token_id = + // llm_model_config.find("eos_token_id") == llm_model_config.end() + // ? -1 + // : (int)llm_model_config.at("eos_token_id"); + if (llm_model_config.find("eos_token_id") != llm_model_config.end()) { + if (llm_model_config["eos_token_id"].is_array()) { + for (auto &eos_token_id : llm_model_config["eos_token_id"]) { + model_metadata.eos_token_ids.push_back(eos_token_id); + } + } else { + model_metadata.eos_token_ids.push_back(llm_model_config["eos_token_id"]); + } + } else { + model_metadata.eos_token_ids.push_back(-1); + } for (auto ssm_model_name : model_metadata.model_names.ssm_model_names) { std::string ssm_config_path = join_path({file_paths.cache_folder_path, @@ -326,7 +339,8 @@ void get_model_meta(FilePaths &file_paths, ModelType ssm_model_type = ModelType::UNKNOWN; auto architectures = ssm_model_config["architectures"]; for (auto const &str : architectures) { - if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM") { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { ssm_model_type = ModelType::LLAMA; break; } else if (str == "OPTForCausalLM") { @@ -344,15 +358,15 @@ void get_model_meta(FilePaths &file_paths, ssm_model_config.find("bos_token_id") == ssm_model_config.end() ? -1 : (int)ssm_model_config.at("bos_token_id"); - int ssm_eos_id = - ssm_model_config.find("eos_token_id") == ssm_model_config.end() - ? -1 - : (int)ssm_model_config.at("eos_token_id"); - if (ssm_bos_id != model_metadata.bos_token_id || - ssm_eos_id != model_metadata.eos_token_id) { - printf("Warning: bos/eos token id mismatch between LLM and one of the " - "SSMs!\n"); - } + // int ssm_eos_id = + // ssm_model_config.find("eos_token_id") == ssm_model_config.end() + // ? -1 + // : (int)ssm_model_config.at("eos_token_id"); + // if (ssm_bos_id != model_metadata.bos_token_id || + // ssm_eos_id != model_metadata.eos_token_id) { + // printf("Warning: bos/eos token id mismatch between LLM and one of the " + // "SSMs!\n"); + // } model_metadata.ssm_model_types.push_back(ssm_model_type); model_metadata.ssm_model_config_paths.push_back(ssm_config_path); model_metadata.ssm_model_weights_paths.push_back(ssm_weights_path); @@ -473,7 +487,7 @@ void FlexFlow::top_level_task(Task const *task, rm->set_streaming_cache(streaming_cache); rm->register_tokenizer(model_metadata.llm_model_type, model_metadata.bos_token_id, - model_metadata.eos_token_id, + model_metadata.eos_token_ids, model_metadata.llm_tokenizer_path); rm->set_decoding_mode(decoding_mode); rm->set_slo_violation_early_termination(slo_attainment_early_termination); diff --git a/inference/trace_generator/trace_generator.cc b/inference/trace_generator/trace_generator.cc index c45c0537fc..14abf59764 100644 --- a/inference/trace_generator/trace_generator.cc +++ b/inference/trace_generator/trace_generator.cc @@ -58,7 +58,8 @@ struct ModelMeta { std::string llm_weights_path; std::string llm_model_config_path; - int bos_token_id, eos_token_id; + int bos_token_id; + std::vector eos_token_ids; std::vector ssm_model_types; std::vector ssm_model_config_paths; @@ -211,7 +212,8 @@ void get_model_meta(FilePaths &file_paths, model_metadata.llm_model_type = ModelType::UNKNOWN; auto architectures = llm_model_config["architectures"]; for (auto const &str : architectures) { - if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM") { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { model_metadata.llm_model_type = ModelType::LLAMA; break; } else if (str == "OPTForCausalLM") { @@ -229,10 +231,21 @@ void get_model_meta(FilePaths &file_paths, llm_model_config.find("bos_token_id") == llm_model_config.end() ? -1 : (int)llm_model_config.at("bos_token_id"); - model_metadata.eos_token_id = - llm_model_config.find("eos_token_id") == llm_model_config.end() - ? -1 - : (int)llm_model_config.at("eos_token_id"); + // model_metadata.eos_token_id = + // llm_model_config.find("eos_token_id") == llm_model_config.end() + // ? -1 + // : (int)llm_model_config.at("eos_token_id"); + if (llm_model_config.find("eos_token_id") != llm_model_config.end()) { + if (llm_model_config["eos_token_id"].is_array()) { + for (auto &eos_token_id : llm_model_config["eos_token_id"]) { + model_metadata.eos_token_ids.push_back(eos_token_id); + } + } else { + model_metadata.eos_token_ids.push_back(llm_model_config["eos_token_id"]); + } + } else { + model_metadata.eos_token_ids.push_back(-1); + } for (auto ssm_model_name : model_metadata.model_names.ssm_model_names) { std::string ssm_config_path = join_path({file_paths.cache_folder_path, @@ -261,7 +274,8 @@ void get_model_meta(FilePaths &file_paths, ModelType ssm_model_type = ModelType::UNKNOWN; auto architectures = ssm_model_config["architectures"]; for (auto const &str : architectures) { - if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM") { + if (str == "LlamaForCausalLM" || str == "LLaMAForCausalLM" || + str == "MistralForCausalLM") { ssm_model_type = ModelType::LLAMA; break; } else if (str == "OPTForCausalLM") { @@ -279,15 +293,15 @@ void get_model_meta(FilePaths &file_paths, ssm_model_config.find("bos_token_id") == ssm_model_config.end() ? -1 : (int)ssm_model_config.at("bos_token_id"); - int ssm_eos_id = - ssm_model_config.find("eos_token_id") == ssm_model_config.end() - ? -1 - : (int)ssm_model_config.at("eos_token_id"); - if (ssm_bos_id != model_metadata.bos_token_id || - ssm_eos_id != model_metadata.eos_token_id) { - printf("Warning: bos/eos token id mismatch between LLM and one of the " - "SSMs!\n"); - } + // int ssm_eos_id = + // ssm_model_config.find("eos_token_id") == ssm_model_config.end() + // ? -1 + // : (int)ssm_model_config.at("eos_token_id"); + // if (ssm_bos_id != model_metadata.bos_token_id || + // ssm_eos_id != model_metadata.eos_token_id) { + // printf("Warning: bos/eos token id mismatch between LLM and one of the " + // "SSMs!\n"); + // } model_metadata.ssm_model_types.push_back(ssm_model_type); model_metadata.ssm_model_config_paths.push_back(ssm_config_path); model_metadata.ssm_model_weights_paths.push_back(ssm_weights_path); @@ -397,7 +411,7 @@ void FlexFlow::top_level_task(Task const *task, rm->set_streaming_cache(streaming_cache); rm->register_tokenizer(model_metadata.llm_model_type, model_metadata.bos_token_id, - model_metadata.eos_token_id, + model_metadata.eos_token_ids, model_metadata.llm_tokenizer_path); rm->set_decoding_mode(decoding_mode); rm->set_slo_violation_early_termination(slo_attainment_early_termination); diff --git a/inference/utils/mem_analysis.py b/inference/utils/mem_analysis.py new file mode 100644 index 0000000000..5168e70039 --- /dev/null +++ b/inference/utils/mem_analysis.py @@ -0,0 +1,115 @@ +import pandas as pd +import re, os, math, argparse + +# Usage: +# Run FlexFlow code with --log-instance-creation flag and redirect the output to a file +# python mem_analysis.py --file_path /path/to/log_file.txt + +def extract_data(file_path): + # Define regex patterns + memory_allocator_pattern = re.compile(r'MemoryAllocator.*memory_kind: (\w+).*memory_id: (\w+).*size: (\d+).*capacity (\d+).*task_name: (.+)') + mapper_pattern = re.compile(r'Mapper.*memory_kind: (\w+).*memory_id: (\w+).*size: (\d+).*capacity (\d+).*task: (.+)') + parallel_tensor_pattern = re.compile(r'ParallelTensor.*memory_kind: (\w+).*memory_id: (\w+).*size: (\d+).*capacity (\d+).*task_name: (.+)') + + # Initialize lists to store extracted data + memory_kinds = [] + memory_ids = [] + sizes = [] + capacities = [] + tasks = [] + + # Read the file + with open(file_path, 'r') as file: + for line in file: + if 'MemoryAllocator' in line: + match = memory_allocator_pattern.search(line) + if match: + memory_kinds.append(match.group(1)) + memory_ids.append(match.group(2)) + sizes.append(int(match.group(3))) + capacities.append(int(match.group(4))) + tasks.append(match.group(5)) + elif 'Mapper' in line: + match = mapper_pattern.search(line) + if match: + memory_kinds.append(match.group(1)) + memory_ids.append(match.group(2)) + sizes.append(int(match.group(3))) + capacities.append(int(match.group(4))) + tasks.append(match.group(5)) + elif 'ParallelTensor' in line: + match = parallel_tensor_pattern.search(line) + if match: + memory_kinds.append(match.group(1)) + memory_ids.append(match.group(2)) + sizes.append(int(match.group(3))) + capacities.append(int(match.group(4))) + tasks.append(match.group(5)) + + # Create a DataFrame + df = pd.DataFrame({ + 'Memory Kind': memory_kinds, + 'Device ID': memory_ids, + 'Size': sizes, + 'Capacity': capacities, + 'Task': tasks + }) + + return df + +def human_readable_size(size_bytes): + if size_bytes == 0: + return "0B" + size_name = ("B", "KB", "MB", "GB", "TB") + i = int(math.floor(math.log(size_bytes, 1000))) + p = math.pow(1000, i) + s = round(size_bytes / p, 2) + return f"{s} {size_name[i]}" + +def print_grouped_by_device(df): + grouped_df = df.groupby(['Memory Kind', 'Device ID']).agg({'Size': 'sum', 'Capacity': 'first'}) + # Check that all entries that share the same memory id have the same capacity + for (memory_kind, memory_id), group in df.groupby(['Memory Kind', 'Device ID']): + capacities = group['Capacity'].unique() + if len(capacities) > 1: + print(f"Warning: Device ID {memory_id} in Memory Kind {memory_kind} has multiple capacities: {capacities}") + # Convert sizes to human-readable format + grouped_df['Size'] = grouped_df['Size'].apply(human_readable_size) + grouped_df['Capacity'] = grouped_df['Capacity'].apply(human_readable_size) + print("############## Memory usage (by device) ##############") + print(grouped_df) + +def print_grouped_by_task(df): + # Group by 'Memory Kind', 'Device ID', and 'Task', and sum the 'Size' column + task_grouped_df = df.groupby(['Memory Kind', 'Device ID', 'Task']).agg({'Size': 'sum'}).reset_index() + # Sort the DataFrame by 'Memory Kind', 'Device ID', and 'Size' in descending order + task_grouped_df = task_grouped_df.sort_values(by=['Memory Kind', 'Device ID', 'Size'], ascending=[True, True, False]) + print("\n\n############## Memory usage (by task) ##############") + for (memory_kind, memory_id), group in task_grouped_df.groupby(['Memory Kind', 'Device ID']): + print("\n-------------------------------------------------------------") + print(f"Memory Kind: {memory_kind}, Device ID: {memory_id}") + group['Size'] = group['Size'].apply(human_readable_size) + print(group[['Task', 'Size']].to_string(index=False)) + print("-------------------------------------------------------------") + +def print_notes(): + print("\n\n############## Notes ##############") + print("* Check that each GPU retains enough capacity in GPU_FB_MEM to hold the weights from Z_COPY_MEM (total size / tp_degree)") + print("* Check whether the memory usage is balanced across devices") + print("* `set_tensor` generally refers to the memory used to load the model weights") + print() + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Analyze memory usage from a FlexFlow log file.') + parser.add_argument('--file_path', '-fp', type=str, help='Path to the input log file') + args = parser.parse_args() + + # Change working directory to the directory holding the script + # script_dir = os.path.dirname(os.path.abspath(__file__)) + # os.chdir(script_dir) + + df = extract_data(args.file_path) + print_grouped_by_device(df) + print_grouped_by_task(df) + + print_notes() \ No newline at end of file diff --git a/python/flexflow/core/__init__.py b/python/flexflow/core/__init__.py index 2820cf485a..24bb158897 100644 --- a/python/flexflow/core/__init__.py +++ b/python/flexflow/core/__init__.py @@ -40,6 +40,7 @@ "zero_copy_memory_per_node": "-ll:zsize", "num_cpus": "-ll:cpu", "legion_utility_processors": "-ll:util", + "log_instance_creation": "--log-instance-creation", "profiling": "--profiling", "benchmarking": "--benchmarking", "inference_debugging": "--inference-debugging", diff --git a/python/flexflow/serve/models/llama.py b/python/flexflow/serve/models/llama.py index 0e59bb547b..e58ed57bcb 100644 --- a/python/flexflow/serve/models/llama.py +++ b/python/flexflow/serve/models/llama.py @@ -280,3 +280,7 @@ def convert_hf_model(model, dst_folder): .replace("model_", "") ) params.detach().cpu().numpy().tofile(f"{dst_folder}/{name}") + # LM head weight + model.lm_head.weight.detach().cpu().numpy().tofile( + os.path.join(dst_folder, "output_weight") + ) diff --git a/python/flexflow/serve/serve.py b/python/flexflow/serve/serve.py index 58c9dc9aaf..37606e8751 100644 --- a/python/flexflow/serve/serve.py +++ b/python/flexflow/serve/serve.py @@ -28,7 +28,6 @@ ) from flexflow.core import * from transformers import AutoConfig, AutoModelForCausalLM -from peft import PeftModel, PeftConfig, LoraConfig from huggingface_hub import HfApi import sys, torch, shutil, hashlib from typing import Union, List @@ -96,6 +95,7 @@ def __init__( self.supported_models = { "LlamaForCausalLM": (ModelType.LLAMA, FlexFlowLLAMA, LLAMAConfig), "LLaMAForCausalLM": (ModelType.LLAMA, FlexFlowLLAMA, LLAMAConfig), + "MistralForCausalLM": (ModelType.LLAMA, FlexFlowLLAMA, LLAMAConfig), "OPTForCausalLM": (ModelType.OPT, FlexFlowOPT, OPTConfig), "RWForCausalLM": (ModelType.FALCON, FlexFlowFalcon, FalconConfig), "FalconForCausalLM": (ModelType.FALCON, FlexFlowFalcon, FalconConfig), @@ -272,7 +272,7 @@ def download_hf_tokenizer_if_needed(self): f"'{self.model_name}' tokenizer needs updating! Downloading tokenizer now..." ) # Load/download the tokenizer files - target_tokenizer_files = ["tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json", "merges.txt"] + target_tokenizer_files = ["tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json", "merges.txt", "tokenizer.model"] if os.path.exists(self.model_name): hf_tokenizer_path = self.model_name else: diff --git a/src/c/flexflow_c.cc b/src/c/flexflow_c.cc index 39d7b1ec56..1ac9a511d5 100644 --- a/src/c/flexflow_c.cc +++ b/src/c/flexflow_c.cc @@ -2711,7 +2711,7 @@ void flexflow_request_manager_register_tokenizer( "Cannot convert nullptr char * to std::string"); std::string const tokenizer_filepath_str(tokenizer_filepath); handle->register_tokenizer( - model_type, bos_token_id, eos_token_id, tokenizer_filepath_str); + model_type, bos_token_id, {eos_token_id}, tokenizer_filepath_str); DEBUG_PRINT( "[RequestManager] register tokenizer %p %s", handle, tokenizer_filepath); } @@ -2831,7 +2831,6 @@ void flexflow_file_data_loader_load_weights(flexflow_file_data_loader_t handle_, flexflow_model_t model_handle_) { FileDataLoader *handle = FFCObjectWrapper::unwrap(handle_); FFModel *model = FFCObjectWrapper::unwrap(model_handle_); - // handle->load_weights(model); Context ctx = model->config.lg_ctx; Runtime *runtime = model->config.lg_hlr; handle->load_weights_parallel(model, ctx, runtime); diff --git a/src/mapper/mapper.cc b/src/mapper/mapper.cc index 5314e9dfe6..38127a1cff 100644 --- a/src/mapper/mapper.cc +++ b/src/mapper/mapper.cc @@ -292,9 +292,7 @@ void FFMapper::select_task_options(MapperContext const ctx, output.initial_proc = all_cpus[0]; return; } - if ((task.task_id == LOAD_FLOAT_WEIGHT_TASK_ID) || - (task.task_id == LOAD_HALF_WEIGHT_TASK_ID) || - (task.task_id == LOAD_QUANT_WEIGHT_TASK_ID)) { + if (task.task_id == LOAD_WEIGHT_TASK_ID) { output.initial_proc = all_cpus[0]; return; } @@ -655,17 +653,18 @@ void FFMapper::map_task(MapperContext const ctx, task.regions[idx], created, &footprint)) { - if (log_instance_creation) { - for (size_t idx = 0; idx < created_instances.size(); idx++) { - log_ff_mapper.print("Instance[%zu]: memory:" IDFMT " proc:" IDFMT - " size:%zu task:%s", - idx, - created_instances[idx].memory.id, - created_instances[idx].processor.id, - created_instances[idx].size, - created_instances[idx].task_name.c_str()); - } - } + // if (log_instance_creation) { + // for (size_t idx = 0; idx < created_instances.size(); idx++) { + // log_ff_mapper.print("Instance[%zu]: memory: " IDFMT " proc: " + // IDFMT + // " size: %zu task: %s", + // idx, + // created_instances[idx].memory.id, + // created_instances[idx].processor.id, + // created_instances[idx].size, + // created_instances[idx].task_name.c_str()); + // } + // } // Report failed to creation log_ff_mapper.error( "Out of memory! FlexFlow failed to reserve block of size %s" @@ -693,6 +692,16 @@ void FFMapper::map_task(MapperContext const ctx, clog.memory = target_mem; clog.processor = task.target_proc; created_instances.push_back(clog); + log_ff_mapper.print( + "Created Instance[%lu]: memory_kind: %s memory_id: %llx " + "proc: " IDFMT " size: %zu (capacity %lu) task: %s", + created_instances.size() - 1, + Legion::Mapping::Utilities::to_string(clog.memory.kind()), + clog.memory.id, + clog.processor.id, + clog.size, + clog.memory.capacity(), + clog.task_name.c_str()); } } // for idx } diff --git a/src/ops/add_bias_residual_layer_norm.cpp b/src/ops/add_bias_residual_layer_norm.cpp index 1add43ecd9..ae66d9b86b 100644 --- a/src/ops/add_bias_residual_layer_norm.cpp +++ b/src/ops/add_bias_residual_layer_norm.cpp @@ -38,7 +38,8 @@ AddBiasResidualLayerNormMeta::AddBiasResidualLayerNormMeta( eps = ln->eps; DataType data_type = ln->data_type; size_t totalSize = effective_batch_size * data_type_size(data_type) * 3; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "AddBiasResidualLayerNormMeta"); mean_ptr = gpu_mem_allocator.allocate_instance_untyped( data_type_size(data_type) * effective_batch_size); rstd_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/add_bias_residual_layer_norm.cu b/src/ops/add_bias_residual_layer_norm.cu index ceb1a6514e..2ce5605b66 100644 --- a/src/ops/add_bias_residual_layer_norm.cu +++ b/src/ops/add_bias_residual_layer_norm.cu @@ -37,7 +37,8 @@ AddBiasResidualLayerNormMeta::AddBiasResidualLayerNormMeta( eps = ln->eps; DataType data_type = ln->data_type; size_t totalSize = effective_batch_size * data_type_size(data_type) * 3; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "AddBiasResidualLayerNormMeta"); mean_ptr = gpu_mem_allocator.allocate_instance_untyped( data_type_size(data_type) * effective_batch_size); rstd_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/arg_topk.cu b/src/ops/arg_topk.cu index fbeb5497c5..a88963aaa3 100644 --- a/src/ops/arg_topk.cu +++ b/src/ops/arg_topk.cu @@ -228,8 +228,8 @@ ArgTopKMeta::ArgTopKMeta(FFHandler handler, MemoryAllocator &gpu_mem_allocator) : OpMeta(handler, op) { max_input_size = BatchConfig::MAX_NUM_TOKENS * 32000; // TODO: use vocab_size - gpu_mem_allocator.create_legion_instance(reserveInst, - sizeof(half) * max_input_size); + gpu_mem_allocator.create_legion_instance( + reserveInst, sizeof(half) * max_input_size, "ArgTopKMeta"); half_precision_output = gpu_mem_allocator.allocate_instance_untyped( sizeof(half) * max_input_size); } diff --git a/src/ops/argmax.cpp b/src/ops/argmax.cpp index 8a1cf0b3b0..bd0b2bd19b 100644 --- a/src/ops/argmax.cpp +++ b/src/ops/argmax.cpp @@ -493,7 +493,8 @@ ArgMaxMeta::ArgMaxMeta(FFHandler handler, size_t prob_size = batch_size; assert(data_type == DT_FLOAT || data_type == DT_HALF); size_t total_size = prob_size * sizeof(float); - gpu_mem_allocator.create_legion_instance(reserveInst, total_size); + gpu_mem_allocator.create_legion_instance( + reserveInst, total_size, "ArgMaxMeta"); probs = gpu_mem_allocator.allocate_instance(prob_size); } ArgMaxMeta::~ArgMaxMeta(void) { diff --git a/src/ops/argmax.cu b/src/ops/argmax.cu index e7baef6d18..42d1a96f35 100644 --- a/src/ops/argmax.cu +++ b/src/ops/argmax.cu @@ -161,7 +161,8 @@ ArgMaxMeta::ArgMaxMeta(FFHandler handler, ? sizeof(cub::KeyValuePair) * batch_size : sizeof(cub::KeyValuePair) * batch_size) + prob_size * sizeof(float); - gpu_mem_allocator.create_legion_instance(reserveInst, total_size); + gpu_mem_allocator.create_legion_instance( + reserveInst, total_size, "ArgMaxMeta"); d_offsets = gpu_mem_allocator.allocate_instance(d_offsets_size); d_out = data_type == DT_FLOAT ? gpu_mem_allocator.allocate_instance_untyped( @@ -200,7 +201,8 @@ ArgMaxMeta::ArgMaxMeta(FFHandler handler, stream)); } - gpu_mem_allocator.create_legion_instance(reserveInst, temp_storage_bytes); + gpu_mem_allocator.create_legion_instance( + reserveInst, temp_storage_bytes, "ArgMaxMeta"); d_temp_storage = gpu_mem_allocator.allocate_instance_untyped(temp_storage_bytes); } diff --git a/src/ops/fused.cc b/src/ops/fused.cc index 6307362ea0..d95cf14695 100644 --- a/src/ops/fused.cc +++ b/src/ops/fused.cc @@ -355,7 +355,7 @@ void FusedOp::init(FFModel const &ff) { false /*must*/, 0 /*mapper_id*/, outputs[0]->machine_view.hash()); - launcher.concurrent = true; + // launcher.concurrent = true; FutureMap fm = runtime->execute_index_space(ctx, launcher); fm.wait_all_results(); switch (domain.get_dim()) { @@ -446,7 +446,7 @@ void FusedOp::init_inference(FFModel const &ff, false /*must*/, 0 /*mapper_id*/, machine_view_hash); - launcher.concurrent = true; + // launcher.concurrent = true; FutureMap fm = runtime->execute_index_space(ctx, launcher); fm.wait_all_results(); switch (domain.get_dim()) { diff --git a/src/ops/fused.cpp b/src/ops/fused.cpp index 9ba9f7b8b3..8b39b8b371 100644 --- a/src/ops/fused.cpp +++ b/src/ops/fused.cpp @@ -1048,7 +1048,7 @@ __host__ void assert(fused->op_num_outputs[op] == 1); AllReduceMeta const *m = (AllReduceMeta *)metas->meta[op]; Kernels::AllReduce::inference_kernel_wrapper( - m, bc, my_input_accessor[0], my_output_accessor[0]); + ctx, runtime, m, bc, my_input_accessor[0], my_output_accessor[0]); break; } default: { diff --git a/src/ops/gumbel_topk.cu b/src/ops/gumbel_topk.cu index 0878eb6fe6..3635fda9cd 100644 --- a/src/ops/gumbel_topk.cu +++ b/src/ops/gumbel_topk.cu @@ -607,7 +607,7 @@ GumbelTopKMeta::GumbelTopKMeta(FFHandler handler, BatchConfig::MAX_NUM_TOKENS * max(BatchConfig::MAX_SPECULATIVE_TREE_BRANCHES, CUDA_NUM_THREADS); gpu_mem_allocator.create_legion_instance( - reserveInst, sizeof(curandState) * state_max_length); + reserveInst, sizeof(curandState) * state_max_length, "GumbelTopKMeta"); state = gpu_mem_allocator.allocate_instance(state_max_length); } diff --git a/src/ops/inc_multihead_self_attention.cpp b/src/ops/inc_multihead_self_attention.cpp index 5e07fa214e..449940155b 100644 --- a/src/ops/inc_multihead_self_attention.cpp +++ b/src/ops/inc_multihead_self_attention.cpp @@ -1010,9 +1010,11 @@ IncMultiHeadSelfAttentionMeta::IncMultiHeadSelfAttentionMeta( assert(gpu_mem_allocator.reserved_total_size - gpu_mem_allocator.reserved_allocated_size >= totalSharedSize); - gpu_mem_allocator.create_legion_instance(reserveInst, instance_size); + gpu_mem_allocator.create_legion_instance( + reserveInst, instance_size, "IncMultiHeadSelfAttentionMeta"); } else { - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "IncMultiHeadSelfAttentionMeta"); } // in tree_verify, enable devQKVProjArray; diff --git a/src/ops/inc_multihead_self_attention.cu b/src/ops/inc_multihead_self_attention.cu index 7472b61f04..e220e82850 100644 --- a/src/ops/inc_multihead_self_attention.cu +++ b/src/ops/inc_multihead_self_attention.cu @@ -568,9 +568,11 @@ IncMultiHeadSelfAttentionMeta::IncMultiHeadSelfAttentionMeta( assert(gpu_mem_allocator.reserved_total_size - gpu_mem_allocator.reserved_allocated_size >= totalSharedSize); - gpu_mem_allocator.create_legion_instance(reserveInst, instance_size); + gpu_mem_allocator.create_legion_instance( + reserveInst, instance_size, "IncMultiHeadSelfAttentionMeta"); } else { - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "IncMultiHeadSelfAttentionMeta"); } // in tree_verify, enable devQKVProjArray; diff --git a/src/ops/kernels/linear_kernels.cu b/src/ops/kernels/linear_kernels.cu index c30c9f71c1..c495e42eb2 100644 --- a/src/ops/kernels/linear_kernels.cu +++ b/src/ops/kernels/linear_kernels.cu @@ -40,7 +40,7 @@ LinearMeta::LinearMeta(FFHandler handler, } // Allocate an all-one's vector gpu_mem_allocator.create_legion_instance( - reserveInst, data_type_size(data_type) * batch_size); + reserveInst, data_type_size(data_type) * batch_size, "LinearMeta"); one_ptr = gpu_mem_allocator.allocate_instance_untyped( data_type_size(data_type) * batch_size); int parallelism = batch_size; diff --git a/src/ops/kernels/residual_rms_norm_kernels.cpp b/src/ops/kernels/residual_rms_norm_kernels.cpp index 6906556452..ed0b0f9a5b 100644 --- a/src/ops/kernels/residual_rms_norm_kernels.cpp +++ b/src/ops/kernels/residual_rms_norm_kernels.cpp @@ -42,7 +42,8 @@ ResidualRMSNormMeta::ResidualRMSNormMeta(FFHandler handler, size_t rms_ptr_size = batch_size; size_t norm_ptr_size = num_elements; size_t totalSize = (rms_ptr_size + norm_ptr_size) * data_type_size(data_type); - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "ResidualRMSNormMeta"); rms_ptr = gpu_mem_allocator.allocate_instance_untyped( rms_ptr_size * data_type_size(data_type)); norm_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/kernels/residual_rms_norm_kernels.cu b/src/ops/kernels/residual_rms_norm_kernels.cu index 2c82308ab5..65125bae1a 100644 --- a/src/ops/kernels/residual_rms_norm_kernels.cu +++ b/src/ops/kernels/residual_rms_norm_kernels.cu @@ -43,7 +43,8 @@ ResidualRMSNormMeta::ResidualRMSNormMeta(FFHandler handler, size_t rms_ptr_size = batch_size; size_t norm_ptr_size = num_elements; size_t totalSize = (rms_ptr_size + norm_ptr_size) * data_type_size(data_type); - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "ResidualRMSNormMeta"); rms_ptr = gpu_mem_allocator.allocate_instance_untyped( rms_ptr_size * data_type_size(data_type)); norm_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/kernels/rms_norm_kernels.cpp b/src/ops/kernels/rms_norm_kernels.cpp index 24ab7051e6..9636929d90 100644 --- a/src/ops/kernels/rms_norm_kernels.cpp +++ b/src/ops/kernels/rms_norm_kernels.cpp @@ -42,7 +42,8 @@ RMSNormMeta::RMSNormMeta(FFHandler handler, size_t rms_ptr_size = batch_size; size_t norm_ptr_size = num_elements; size_t totalSize = (rms_ptr_size + norm_ptr_size) * data_type_size(data_type); - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "RMSNormMeta"); rms_ptr = gpu_mem_allocator.allocate_instance_untyped( rms_ptr_size * data_type_size(data_type)); norm_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/kernels/rms_norm_kernels.cu b/src/ops/kernels/rms_norm_kernels.cu index 7c9f4a9f98..8555e58beb 100644 --- a/src/ops/kernels/rms_norm_kernels.cu +++ b/src/ops/kernels/rms_norm_kernels.cu @@ -43,7 +43,8 @@ RMSNormMeta::RMSNormMeta(FFHandler handler, size_t rms_ptr_size = batch_size; size_t norm_ptr_size = num_elements; size_t totalSize = (rms_ptr_size + norm_ptr_size) * data_type_size(data_type); - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "RMSNormMeta"); rms_ptr = gpu_mem_allocator.allocate_instance_untyped( rms_ptr_size * data_type_size(data_type)); norm_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/layer_norm.cu b/src/ops/layer_norm.cu index 44979c48fe..4289a92369 100644 --- a/src/ops/layer_norm.cu +++ b/src/ops/layer_norm.cu @@ -37,7 +37,8 @@ LayerNormMeta::LayerNormMeta(FFHandler handle, eps = ln->eps; DataType data_type = ln->data_type; size_t totalSize = effective_batch_size * data_type_size(data_type) * 6; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "LayerNormMeta"); mean_ptr = gpu_mem_allocator.allocate_instance_untyped( data_type_size(data_type) * effective_batch_size); rstd_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/residual_layer_norm.cpp b/src/ops/residual_layer_norm.cpp index f1b7a537b0..046a4bc250 100644 --- a/src/ops/residual_layer_norm.cpp +++ b/src/ops/residual_layer_norm.cpp @@ -38,7 +38,8 @@ ResidualLayerNormMeta::ResidualLayerNormMeta(FFHandler handle, eps = ln->eps; DataType data_type = ln->data_type; size_t totalSize = effective_batch_size * data_type_size(data_type) * 3; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "ResidualLayerNormMeta"); mean_ptr = gpu_mem_allocator.allocate_instance_untyped( data_type_size(data_type) * effective_batch_size); rstd_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/residual_layer_norm.cu b/src/ops/residual_layer_norm.cu index e5ebdce6ed..05e66db02b 100644 --- a/src/ops/residual_layer_norm.cu +++ b/src/ops/residual_layer_norm.cu @@ -37,7 +37,8 @@ ResidualLayerNormMeta::ResidualLayerNormMeta(FFHandler handle, eps = ln->eps; DataType data_type = ln->data_type; size_t totalSize = effective_batch_size * data_type_size(data_type) * 3; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "ResidualLayerNormMeta"); mean_ptr = gpu_mem_allocator.allocate_instance_untyped( data_type_size(data_type) * effective_batch_size); rstd_ptr = gpu_mem_allocator.allocate_instance_untyped( diff --git a/src/ops/sampling.cpp b/src/ops/sampling.cpp index 3d8f103524..03e37333e6 100644 --- a/src/ops/sampling.cpp +++ b/src/ops/sampling.cpp @@ -204,7 +204,8 @@ SamplingMeta::SamplingMeta(FFHandler handler, idx_size + sorted_idx_size) + data_type_size(data_type) * sorted_logits_size + sizeof(hiprandState) * state_size; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "SamplingMeta"); begin_offset = gpu_mem_allocator.allocate_instance(begin_offset_size); end_offset = gpu_mem_allocator.allocate_instance(end_offset_size); idx = gpu_mem_allocator.allocate_instance(idx_size); @@ -262,7 +263,8 @@ SamplingMeta::SamplingMeta(FFHandler handler, // assert(false && "input type in float and half"); // } - gpu_mem_allocator.create_legion_instance(reserveInst, temp_storage_bytes); + gpu_mem_allocator.create_legion_instance( + reserveInst, temp_storage_bytes, "SamplingMeta"); d_temp_storage = gpu_mem_allocator.allocate_instance_untyped(temp_storage_bytes); } diff --git a/src/ops/sampling.cu b/src/ops/sampling.cu index 494a5ab3f3..6868170968 100644 --- a/src/ops/sampling.cu +++ b/src/ops/sampling.cu @@ -228,7 +228,8 @@ SamplingMeta::SamplingMeta(FFHandler handler, idx_size + sorted_idx_size) + data_type_size(data_type) * sorted_logits_size + sizeof(curandState) * state_size; - gpu_mem_allocator.create_legion_instance(reserveInst, totalSize); + gpu_mem_allocator.create_legion_instance( + reserveInst, totalSize, "SamplingMeta"); begin_offset = gpu_mem_allocator.allocate_instance(begin_offset_size); end_offset = gpu_mem_allocator.allocate_instance(end_offset_size); idx = gpu_mem_allocator.allocate_instance(idx_size); @@ -286,7 +287,8 @@ SamplingMeta::SamplingMeta(FFHandler handler, assert(false && "input type in float and half"); } - gpu_mem_allocator.create_legion_instance(reserveInst, temp_storage_bytes); + gpu_mem_allocator.create_legion_instance( + reserveInst, temp_storage_bytes, "SamplingMeta"); d_temp_storage = gpu_mem_allocator.allocate_instance_untyped(temp_storage_bytes); } diff --git a/src/ops/spec_inc_multihead_self_attention.cc b/src/ops/spec_inc_multihead_self_attention.cc index 303fb9aa75..2e5cc9fa7a 100644 --- a/src/ops/spec_inc_multihead_self_attention.cc +++ b/src/ops/spec_inc_multihead_self_attention.cc @@ -204,6 +204,8 @@ Tensor FFModel::spec_inc_multiquery_self_attention( li->add_int_property("qk_prod_scaling", qk_prod_scaling); li->add_int_property("position_bias", position_bias); li->add_int_property("streaming_cache", streaming_cache); + li->add_int_property("tensor_parallelism_degree", + config.tensor_parallelism_degree); layers.push_back(li); return li->outputs[0]; } @@ -255,6 +257,8 @@ Op *SpecIncMultiHeadSelfAttention::create_operator_from_layer( bool position_bias = (bool)value; layer->get_int_property("streaming_cache", value); bool streaming_cache = (bool)value; + layer->get_int_property("tensor_parallelism_degree", value); + int tensor_parallelism_degree = (int)value; return new SpecIncMultiHeadSelfAttention(model, layer->layer_guid, @@ -275,6 +279,7 @@ Op *SpecIncMultiHeadSelfAttention::create_operator_from_layer( position_bias, false /*allocate_weights*/, streaming_cache, + tensor_parallelism_degree, layer->name); } @@ -298,6 +303,7 @@ SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( bool _position_bias, bool allocate_weights, bool _streaming_cache, + int _tensor_parallelism_degree, char const *name) // Initializer* _bias_initializer) : Op(model, @@ -316,7 +322,8 @@ SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( o_dim(_embed_dim), qoSeqLength(_input->dims[1].size), kvSeqLength(_input->dims[1].size), scaling_query(_scaling_query), scaling_factor(_scaling_factor), qk_prod_scaling(_qk_prod_scaling), - position_bias(_position_bias), streaming_cache(_streaming_cache) { + position_bias(_position_bias), streaming_cache(_streaming_cache), + tensor_parallelism_degree(_tensor_parallelism_degree) { // overwrite layer_guid layer_guid = _layer_guid; @@ -399,6 +406,7 @@ SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( bool _position_bias, bool allocate_weights, bool _streaming_cache, + int _tensor_parallelism_degree, char const *name) // Initializer* _bias_initializer) : Op(model, @@ -418,7 +426,8 @@ SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( o_dim(_embed_dim), qoSeqLength(_input->dims[1].size), kvSeqLength(_input->dims[1].size), scaling_query(_scaling_query), scaling_factor(_scaling_factor), qk_prod_scaling(_qk_prod_scaling), - position_bias(_position_bias), streaming_cache(_streaming_cache) + position_bias(_position_bias), streaming_cache(_streaming_cache), + tensor_parallelism_degree(_tensor_parallelism_degree) // bias_initializer(_bias_initializer) { numOutputs = 1; @@ -508,6 +517,7 @@ SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( other.position_bias, allocate_weights, other.streaming_cache, + other.tensor_parallelism_degree, other.name) {} SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( @@ -535,6 +545,7 @@ SpecIncMultiHeadSelfAttention::SpecIncMultiHeadSelfAttention( params.position_bias, allocate_weights, params.streaming_cache, + params.tensor_parallelism_degree, params.name) {} void SpecIncMultiHeadSelfAttention::init_inference( @@ -660,8 +671,10 @@ OpMeta *SpecIncMultiHeadSelfAttention::init_task( int num_samples = input.domain.hi()[2] - input.domain.lo()[2] + 1; assert(attn->qoSeqLength == input.domain.hi()[1] - input.domain.lo()[1] + 1); assert(attn->kvSeqLength == input.domain.hi()[1] - input.domain.lo()[1] + 1); - int num_q_heads = attn->num_q_heads; - int num_kv_heads = attn->num_kv_heads; + int num_q_heads = attn->num_q_heads / attn->tensor_parallelism_degree; + int num_kv_heads = + attn->num_kv_heads / attn->tensor_parallelism_degree + + (attn->num_kv_heads % attn->tensor_parallelism_degree != 0); assert(attn->o_dim == output.domain.hi()[0] - output.domain.lo()[0] + 1); Memory gpu_mem = Machine::MemoryQuery(Machine::get_machine()) @@ -891,6 +904,7 @@ SpecIncMultiHeadSelfAttentionParams params.qk_prod_scaling = this->qk_prod_scaling; params.position_bias = this->position_bias; params.streaming_cache = this->streaming_cache; + params.tensor_parallelism_degree = this->tensor_parallelism_degree; if (this->name != nullptr) { strcpy(params.name, this->name); } @@ -927,6 +941,7 @@ size_t hash::operator()( hash_combine(key, params.qk_prod_scaling); hash_combine(key, params.position_bias); hash_combine(key, params.streaming_cache); + hash_combine(key, params.tensor_parallelism_degree); return key; } }; // namespace std diff --git a/src/ops/spec_inc_multihead_self_attention.cpp b/src/ops/spec_inc_multihead_self_attention.cpp index e797d40d3c..92bcbc546a 100644 --- a/src/ops/spec_inc_multihead_self_attention.cpp +++ b/src/ops/spec_inc_multihead_self_attention.cpp @@ -634,8 +634,10 @@ SpecIncMultiHeadSelfAttentionMeta::SpecIncMultiHeadSelfAttentionMeta( // be added here later // We always directly allocate memory for small speculative models - gpu_mem_allocator.create_legion_instance(beam_search_reserve_inst, - total_size); + gpu_mem_allocator.create_legion_instance( + beam_search_reserve_inst, + total_size, + "SpecIncMultiHeadSelfAttentionMeta"); beam_token_infos = gpu_mem_allocator .allocate_instance( diff --git a/src/ops/tree_inc_multihead_self_attention.cpp b/src/ops/tree_inc_multihead_self_attention.cpp index f748dafd65..cf3426b3e4 100644 --- a/src/ops/tree_inc_multihead_self_attention.cpp +++ b/src/ops/tree_inc_multihead_self_attention.cpp @@ -643,8 +643,10 @@ TreeIncMultiHeadSelfAttentionMeta::TreeIncMultiHeadSelfAttentionMeta( gpu_mem_allocator.allocate_reserved( committed_tokeninfo_size); } else { - gpu_mem_allocator.create_legion_instance(committed_token_reserve_inst, - total_size); + gpu_mem_allocator.create_legion_instance( + committed_token_reserve_inst, + total_size, + "TreeIncMultiHeadSelfAttentionMeta"); committed_token_infos = gpu_mem_allocator.allocate_instance( committed_tokeninfo_size); diff --git a/src/parallel_ops/allreduce.cc b/src/parallel_ops/allreduce.cc index c7b7a74337..7f38e27148 100644 --- a/src/parallel_ops/allreduce.cc +++ b/src/parallel_ops/allreduce.cc @@ -134,7 +134,7 @@ void AllReduce::init(FFModel const &ff) { false /*must*/, 0 /*mapper_id*/, outputs[0]->machine_view.hash()); - launcher.concurrent = true; + // launcher.concurrent = true; launcher.add_region_requirement(RegionRequirement(inputs[0]->part, 0 /*projection id*/, READ_ONLY, @@ -173,7 +173,7 @@ void AllReduce::init_inference(FFModel const &ff, false /*must*/, 0 /*mapper_id*/, machine_view_hash); - launcher.concurrent = true; + // launcher.concurrent = true; launcher.add_region_requirement(RegionRequirement(batch_inputs[0]->part, 0 /*projection id*/, READ_ONLY, @@ -278,7 +278,7 @@ void AllReduce::backward(FFModel const &ff) { false /*must*/, 0 /*mapper_id*/, inputs[0]->machine_view.hash()); - launcher.concurrent = true; + // launcher.concurrent = true; launcher.add_region_requirement(RegionRequirement(inputs[0]->part_grad, 0 /*projection id*/, READ_WRITE, diff --git a/src/parallel_ops/kernels/allreduce_kernels.cpp b/src/parallel_ops/kernels/allreduce_kernels.cpp index 8d7e20e395..1e60728faa 100644 --- a/src/parallel_ops/kernels/allreduce_kernels.cpp +++ b/src/parallel_ops/kernels/allreduce_kernels.cpp @@ -25,7 +25,9 @@ AllReduceMeta::AllReduceMeta(FFHandler handle, AllReduce const *reduct) namespace Kernels { namespace AllReduce { -void inference_kernel_wrapper(AllReduceMeta const *m, +void inference_kernel_wrapper(Legion::Context ctx, + Legion::Runtime *runtime, + AllReduceMeta const *m, BatchConfig const *bc, GenericTensorAccessorR const &input, GenericTensorAccessorW const &output) { @@ -37,6 +39,7 @@ void inference_kernel_wrapper(AllReduceMeta const *m, size_t num_elements = bc->num_tokens * hidden_dim_size; #ifdef FF_USE_NCCL ncclDataType_t nccl_data_type = ff_to_nccl_datatype(input.data_type); + runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllReduce(input.ptr, output.ptr, num_elements, @@ -44,12 +47,15 @@ void inference_kernel_wrapper(AllReduceMeta const *m, ncclSum, m->handle.ncclComm, stream)); + runtime->concurrent_task_barrier(ctx); #else assert(false && "Must enable FF_USE_NCCL to use AllReduce operators"); #endif } -void forward_kernel_wrapper(AllReduceMeta const *m, +void forward_kernel_wrapper(Legion::Context ctx, + Legion::Runtime *runtime, + AllReduceMeta const *m, GenericTensorAccessorR const &input, GenericTensorAccessorW const &output) { hipStream_t stream; @@ -59,6 +65,7 @@ void forward_kernel_wrapper(AllReduceMeta const *m, size_t hidden_dim_size = input.domain.hi()[0] - input.domain.lo()[0] + 1; #ifdef FF_USE_NCCL ncclDataType_t nccl_data_type = ff_to_nccl_datatype(input.data_type); + runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllReduce(input.ptr, output.ptr, input.domain.get_volume(), @@ -66,6 +73,7 @@ void forward_kernel_wrapper(AllReduceMeta const *m, ncclSum, m->handle.ncclComm, stream)); + runtime->concurrent_task_barrier(ctx); #else assert(false && "Must enable FF_USE_NCCL to use AllReduce operators"); #endif diff --git a/src/parallel_ops/kernels/allreduce_kernels.cu b/src/parallel_ops/kernels/allreduce_kernels.cu index 52bd05b060..8644a5a3cf 100644 --- a/src/parallel_ops/kernels/allreduce_kernels.cu +++ b/src/parallel_ops/kernels/allreduce_kernels.cu @@ -29,7 +29,8 @@ AllReduceMeta::AllReduceMeta(FFHandler handle, tensorrt_llm::MAX_RANKS_PER_NODE; gpu_mem_allocator.create_legion_instance( reserveInst, - sizeof(void *) * (handle.num_devices + 1) + barrier_ptr_size * 2); + sizeof(void *) * (handle.num_devices + 1) + barrier_ptr_size * 2, + "AllReduceMeta"); allgather_src = gpu_mem_allocator.allocate_instance_untyped(sizeof(void *)); allgather_dst = gpu_mem_allocator.allocate_instance_untyped( sizeof(void *) * handle.num_devices); @@ -57,7 +58,9 @@ AllReduceMeta::~AllReduceMeta() { namespace Kernels { namespace AllReduce { -CommunicationBuffer *get_or_create_comm_buffer(AllReduceMeta *m, +CommunicationBuffer *get_or_create_comm_buffer(Legion::Context ctx, + Legion::Runtime *runtime, + AllReduceMeta *m, int num_devices, int device_id, ncclComm_t ncclComm, @@ -68,7 +71,9 @@ CommunicationBuffer *get_or_create_comm_buffer(AllReduceMeta *m, return iter->second; } else { CommunicationBuffer *comm_buffer = - create_comm_buf_with_local_ptr(num_devices, + create_comm_buf_with_local_ptr(ctx, + runtime, + num_devices, device_id, ncclComm, m->allgather_src, @@ -118,8 +123,8 @@ inline bool CanApplyTwoShotAllReduce(int64_t num_elements, } // Customized all-reduce kernel backed by CUDA Peer memory. -void inference_kernel_wrapper(Context ctx, - Runtime *runtime, +void inference_kernel_wrapper(Legion::Context ctx, + Legion::Runtime *runtime, AllReduceMeta *m, BatchConfig const *bc, GenericTensorAccessorR const &input, @@ -133,68 +138,72 @@ void inference_kernel_wrapper(Context ctx, assert(input.domain == output.domain); size_t hidden_dim_size = input.domain.hi()[0] - input.domain.lo()[0] + 1; size_t num_elements = bc->num_tokens * hidden_dim_size; - int num_devices = m->handle.num_devices; - int device_id = m->handle.device_id; + // int num_devices = m->handle.num_devices; + // int device_id = m->handle.device_id; ncclComm_t ncclComm = m->handle.ncclComm; DataType dtype = input.data_type; - tensorrt_llm::AllReduceStrategyType strategy = - tensorrt_llm::SelectImplementation( - num_elements * ((get_bits(dtype) + 7) / 8), num_devices); + // tensorrt_llm::AllReduceStrategyType strategy = + // tensorrt_llm::SelectImplementation( + // num_elements * ((get_bits(dtype) + 7) / 8), num_devices); - if (strategy == tensorrt_llm::AllReduceStrategyType::RING || - !CanApplyCustomAllReduce(num_elements, dtype)) { + // if (strategy == tensorrt_llm::AllReduceStrategyType::RING || + // !CanApplyCustomAllReduce(num_elements, dtype)) { // Dispatch to nccl AllReduce if the customized all-reduce cannot apply. - ncclDataType_t nccl_data_type = ff_to_nccl_datatype(dtype); - runtime->concurrent_task_barrier(ctx); - checkNCCL(ncclAllReduce(input.ptr, - output.ptr, - num_elements, - nccl_data_type, - ncclSum, - ncclComm, - stream)); - runtime->concurrent_task_barrier(ctx); - return; - } - - // Initialize the all-reduce kernel arguments. - tensorrt_llm::AllReduceParams params; - params.ranks_per_node = num_devices; - params.rank = device_id; - params.local_rank = device_id; - CommunicationBuffer *comm_buffer = - get_or_create_comm_buffer(m, - num_devices, - device_id, - ncclComm, - const_cast(input.ptr), - stream); - params.barrier_flag = ++(*comm_buffer->barrier_flag); - for (int i = 0; i < num_devices; ++i) { - params.peer_comm_buffer_ptrs[i] = comm_buffer->comm_ptrs[i]; - } - for (int i = 0; i < num_devices; ++i) { - params.peer_barrier_ptrs_in[i] = - reinterpret_cast(comm_buffer->barrier_in[i]); - } - for (int i = 0; i < num_devices; ++i) { - params.peer_barrier_ptrs_out[i] = - reinterpret_cast(comm_buffer->barrier_out[i]); - } - - if (!CanApplyTwoShotAllReduce(num_elements, dtype, num_devices)) { - // Two-shot all-reduce does not support this case. - // So we fallback to the one-shot strategy. - strategy = tensorrt_llm::AllReduceStrategyType::ONESHOT; - } - - tensorrt_llm::customAllReduce( - params, output.ptr, num_elements, dtype, strategy, stream); + ncclDataType_t nccl_data_type = ff_to_nccl_datatype(dtype); + runtime->concurrent_task_barrier(ctx); + checkNCCL(ncclAllReduce(input.ptr, + output.ptr, + num_elements, + nccl_data_type, + ncclSum, + ncclComm, + stream)); + runtime->concurrent_task_barrier(ctx); + // return; + // } + + // // Initialize the all-reduce kernel arguments. + // tensorrt_llm::AllReduceParams params; + // params.ranks_per_node = num_devices; + // params.rank = device_id; + // params.local_rank = device_id; + // CommunicationBuffer *comm_buffer = + // get_or_create_comm_buffer(ctx, + // runtime, + // m, + // num_devices, + // device_id, + // ncclComm, + // const_cast(input.ptr), + // stream); + // params.barrier_flag = ++(*comm_buffer->barrier_flag); + // for (int i = 0; i < num_devices; ++i) { + // params.peer_comm_buffer_ptrs[i] = comm_buffer->comm_ptrs[i]; + // } + // for (int i = 0; i < num_devices; ++i) { + // params.peer_barrier_ptrs_in[i] = + // reinterpret_cast(comm_buffer->barrier_in[i]); + // } + // for (int i = 0; i < num_devices; ++i) { + // params.peer_barrier_ptrs_out[i] = + // reinterpret_cast(comm_buffer->barrier_out[i]); + // } + + // if (!CanApplyTwoShotAllReduce(num_elements, dtype, num_devices)) { + // // Two-shot all-reduce does not support this case. + // // So we fallback to the one-shot strategy. + // strategy = tensorrt_llm::AllReduceStrategyType::ONESHOT; + // } + + // runtime->concurrent_task_barrier(ctx); + // tensorrt_llm::customAllReduce( + // params, output.ptr, num_elements, dtype, strategy, stream); + // runtime->concurrent_task_barrier(ctx); } -void forward_kernel_wrapper(Context ctx, - Runtime *runtime, +void forward_kernel_wrapper(Legion::Context ctx, + Legion::Runtime *runtime, AllReduceMeta const *m, GenericTensorAccessorR const &input, GenericTensorAccessorW const &output) { diff --git a/src/runtime/batch_config.cc b/src/runtime/batch_config.cc index b5d4c10ce6..ba110f6762 100644 --- a/src/runtime/batch_config.cc +++ b/src/runtime/batch_config.cc @@ -129,6 +129,16 @@ std::ostream &operator<<(std::ostream &os, return os; } +std::ostream &operator<<(std::ostream &os, BatchConfig::BitMask const &bm) { + os << "BitMask {\n" + << " non_tree_cache_size: " << bm.non_tree_cache_size << "\n" + << " tree_or_prompt_size: " << bm.tree_or_prompt_size << "\n" + << " current_layer_size: " << bm.current_layer_size << "\n" + << " bit_mask: [" << bm.bit_mask << "]\n"; + os << "}"; + return os; +} + std::ostream &operator<<(std::ostream &os, BatchConfig const &bc) { os << "@@@@@@@@@@@@@@ Batch Config (mode " << bc.get_mode() << ") @@@@@@@@@@@@@@" << std::endl; @@ -241,6 +251,38 @@ std::ostream &operator<<(std::ostream &os, BatchConfig const &bc) { return os; } +std::ostream &operator<<(std::ostream &os, InferenceResult const &ir) { + os << "InferenceResult {\n" + << " num_token_ids: " << ir.num_token_ids << "\n" + << " num_gumbel_logits: " << ir.num_gumbel_logits << "\n" + << " token_ids: ["; + for (int i = 0; i < ir.num_token_ids; i++) { + os << ir.token_ids[i]; + if (i < ir.num_token_ids - 1) { + os << ", "; + } + } + os << "]\n" + << " probs: ["; + for (int i = 0; i < ir.num_token_ids; i++) { + os << ir.probs[i]; + if (i < ir.num_token_ids - 1) { + os << ", "; + } + } + os << "]\n" + << " gumbel_logits: ["; + for (int i = 0; i < ir.num_gumbel_logits; i++) { + os << ir.gumbel_logits[i]; + if (i < ir.num_gumbel_logits - 1) { + os << ", "; + } + } + os << "]\n" + << "}"; + return os; +} + void BatchConfig::print() const { std::cout << *this << std::endl; } diff --git a/src/runtime/file_loader.cc b/src/runtime/file_loader.cc index bd6a862d02..14e806d497 100644 --- a/src/runtime/file_loader.cc +++ b/src/runtime/file_loader.cc @@ -650,14 +650,21 @@ void load_from_quantized_file(char *ptr, void FileDataLoader::load_quantization_weight(FFModel *ff, Layer *l, - int weight_idx) { - Tensor weight = l->weights[weight_idx]; - size_t volume = 1; + int weight_idx, + size_t volume, + size_t num_replicas, + char *weight, + DataType data_type, + Domain weight_domain) { + // Tensor weight = l->weights[weight_idx]; + size_t volume_ = 1; std::vector dims_vec; - for (int i = 0; i < weight->num_dims; i++) { - dims_vec.push_back(weight->dims[i]); - volume *= weight->dims[i]; + for (int i = 0; i < weight_domain.get_dim(); i++) { + int dim_i = weight_domain.hi()[i] - weight_domain.lo()[i] + 1; + dims_vec.push_back(dim_i); + volume_ *= dim_i; } + assert(volume_ == volume * num_replicas); char *data = (char *)malloc(sizeof(char) * volume); std::string weight_filename = removeGuidOperatorName(std::string(l->name)); @@ -672,7 +679,7 @@ void FileDataLoader::load_quantization_weight(FFModel *ff, head_dim, weight_filename, weights_folder, - weight->data_type, + data_type, use_full_precision); } // else { @@ -694,13 +701,18 @@ void FileDataLoader::load_quantization_weight(FFModel *ff, load_from_quantized_file(data, volume, join_path({weights_folder, weight_filename}), - weight->data_type, + data_type, use_full_precision); } - ParallelTensor weight_pt; - ff->get_parallel_tensor_from_tensor(weight, weight_pt); - weight_pt->set_tensor(ff, dims_vec, data); + // ParallelTensor weight_pt; + // ff->get_parallel_tensor_from_tensor(weight, weight_pt); + // weight_pt->set_tensor(ff, dims_vec, data); + char *ptr = weight; + for (size_t i = 0; i < num_replicas; i++) { + memcpy(ptr, data, volume * sizeof(char)); + ptr += volume; + } free(data); } @@ -708,17 +720,22 @@ void FileDataLoader::load_quantization_weight(FFModel *ff, template void FileDataLoader::load_single_weight_tensor(FFModel *ff, Layer *l, - int weight_idx) { - Tensor weight = l->weights[weight_idx]; + int weight_idx, + size_t volume, + size_t num_replicas, + DT *weight, + Domain weight_domain) { // Create a buffer to store weight data from the file - size_t volume = 1; + size_t volume_ = 1; std::vector dims_vec; - for (int i = 0; i < weight->num_dims; i++) { - dims_vec.push_back(weight->dims[i]); - volume *= weight->dims[i]; + for (int i = 0; i < weight_domain.get_dim(); i++) { + int dim_i = weight_domain.hi()[i] - weight_domain.lo()[i] + 1; + dims_vec.push_back(dim_i); + volume_ *= dim_i; } - assert(data_type_size(weight->data_type) == sizeof(DT)); + assert(volume_ == volume * num_replicas); + // assert(data_type_size(weight->data_type) == sizeof(DT)); DT *data = (DT *)malloc(sizeof(DT) * volume); std::string weight_filename = removeGuidOperatorName(std::string(l->name)); @@ -778,74 +795,67 @@ void FileDataLoader::load_single_weight_tensor(FFModel *ff, } } - // Copy the weight data from the buffer to the weight's ParallelTensor - ParallelTensor weight_pt; - ff->get_parallel_tensor_from_tensor(weight, weight_pt); - weight_pt->set_tensor
(ff, dims_vec, data); + // Copy the weight data from the buffer to the weight + DT *ptr = weight; + for (size_t i = 0; i < num_replicas; i++) { + memcpy(ptr, data, volume * sizeof(DT)); + ptr += volume; + } // Free buffer memory free(data); } -#ifdef DEADCODE -void FileDataLoader::load_weights(FFModel *ff) { - for (Layer *l : ff->layers) { - if (l->numWeights < 1 || l->name == NULL || strlen(l->name) < 1) { - continue; - } - for (int i = 0; i < l->numWeights; i++) { - Tensor weight = l->weights[i]; - if (weight == NULL) { - continue; - } - switch (weight->data_type) { - case DT_HALF: - load_single_weight_tensor(ff, l, i); - break; - case DT_FLOAT: - load_single_weight_tensor(ff, l, i); - break; - case DT_INT4: - case DT_INT8: - // load weights in quantization - load_quantization_weight(ff, l, i); - break; - default: - assert(false && "Unsupported data type"); - } - } - } -} -#endif - -void FileDataLoader::load_float_weight_task( +void FileDataLoader::load_weight_task( Legion::Task const *task, std::vector const ®ions, Legion::Context ctx, Legion::Runtime *runtime) { WeightLoadTaskArgs const *args = (WeightLoadTaskArgs const *)task->args; - args->loader->load_single_weight_tensor( - args->ff, args->layer, args->weight_idx); -} -void FileDataLoader::load_half_weight_task( - Legion::Task const *task, - std::vector const ®ions, - Legion::Context ctx, - Legion::Runtime *runtime) { - WeightLoadTaskArgs const *args = (WeightLoadTaskArgs const *)task->args; - args->loader->load_single_weight_tensor( - args->ff, args->layer, args->weight_idx); -} - -void FileDataLoader::load_quant_weight_task( - Legion::Task const *task, - std::vector const ®ions, - Legion::Context ctx, - Legion::Runtime *runtime) { - WeightLoadTaskArgs const *args = (WeightLoadTaskArgs const *)task->args; - args->loader->load_quantization_weight( - args->ff, args->layer, args->weight_idx); + assert(task->regions.size() == regions.size()); + assert(regions.size() == 1); // one weight only + GenericTensorAccessorW weight = helperGetGenericTensorAccessorWO( + args->data_type, regions[0], task->regions[0], FID_DATA, ctx, runtime); + Domain weight_domain = runtime->get_index_space_domain( + ctx, task->regions[0].region.get_index_space()); + + switch (args->data_type) { + case DT_HALF: { + args->loader->load_single_weight_tensor(args->ff, + args->layer, + args->weight_idx, + args->volume, + args->num_replicas, + weight.get_half_ptr(), + weight_domain); + break; + } + case DT_FLOAT: { + args->loader->load_single_weight_tensor(args->ff, + args->layer, + args->weight_idx, + args->volume, + args->num_replicas, + weight.get_float_ptr(), + weight_domain); + break; + } + case DT_INT4: + case DT_INT8: { + args->loader->load_quantization_weight(args->ff, + args->layer, + args->weight_idx, + args->volume, + args->num_replicas, + weight.get_byte_ptr(), + args->data_type, + weight_domain); + break; + } + default: + assert(false && "Unsupported data type"); + } } void FileDataLoader::load_weights_parallel(FFModel *ff, @@ -857,41 +867,46 @@ void FileDataLoader::load_weights_parallel(FFModel *ff, if (l->numWeights < 1 || l->name == NULL || strlen(l->name) < 1) { continue; } + for (int i = 0; i < l->numWeights; i++) { Tensor weight = l->weights[i]; if (weight == NULL) { continue; } + if (weight->data_type != DT_FLOAT && weight->data_type != DT_HALF && + weight->data_type != DT_INT4 && weight->data_type != DT_INT8) { + assert(false && "Unsupported data type"); + } + + ParallelTensor weight_pt; + ff->get_parallel_tensor_from_tensor(weight, weight_pt); + // Create task arguments - WeightLoadTaskArgs args(ff, this, l, i); - - switch (weight->data_type) { - case DT_HALF: { - TaskLauncher launcher( - LOAD_HALF_WEIGHT_TASK_ID, - TaskArgument(&args, sizeof(WeightLoadTaskArgs))); - futures.push_back(runtime->execute_task(ctx, launcher)); - break; - } - case DT_FLOAT: { - TaskLauncher launcher( - LOAD_FLOAT_WEIGHT_TASK_ID, - TaskArgument(&args, sizeof(WeightLoadTaskArgs))); - futures.push_back(runtime->execute_task(ctx, launcher)); - break; - } - case DT_INT4: - case DT_INT8: { - TaskLauncher launcher( - LOAD_QUANT_WEIGHT_TASK_ID, - TaskArgument(&args, sizeof(WeightLoadTaskArgs))); - futures.push_back(runtime->execute_task(ctx, launcher)); - break; + size_t volume = 1, num_replicas = 1; + if (weight_pt->sync_type == ParameterSyncType::NCCL) { + for (int i = 0; i < weight_pt->num_dims; i++) { + if (weight_pt->dims[i].is_replica_dim) { + num_replicas *= weight_pt->dims[i].size; + } } - default: - assert(false && "Unsupported data type"); + } else if (weight_pt->sync_type == ParameterSyncType::PS) { + num_replicas = 1; + } else { + num_replicas = 1; + } + for (int i = 0; i < weight->num_dims; i++) { + volume *= weight->dims[i]; } + WeightLoadTaskArgs args( + ff, this, l, i, volume, num_replicas, weight->data_type); + // launch task asynchronously + TaskLauncher launcher(LOAD_WEIGHT_TASK_ID, + TaskArgument(&args, sizeof(WeightLoadTaskArgs))); + launcher.add_region_requirement(RegionRequirement( + weight_pt->region, WRITE_ONLY, EXCLUSIVE, weight_pt->region)); + launcher.add_field(0, FID_DATA); + futures.push_back(runtime->execute_task(ctx, launcher)); } } diff --git a/src/runtime/graph.cc b/src/runtime/graph.cc index 326f446aad..30f42327f2 100644 --- a/src/runtime/graph.cc +++ b/src/runtime/graph.cc @@ -2388,6 +2388,7 @@ GraphOptimalViewSerialized sez.serialize(attn->position_bias); sez.serialize(attn->streaming_cache); sez.serialize(attn->num_kv_heads); + sez.serialize(attn->tensor_parallelism_degree); sez.serialize(strlen(attn->name)); sez.serialize(attn->name, strlen(attn->name)); break; @@ -2903,7 +2904,8 @@ void FFModel::deserialize_graph_optimal_view( } case OP_SPEC_INC_MULTIHEAD_SELF_ATTENTION: { assert(num_inputs == 1); - int embed_dim, num_q_heads, k_dim, v_dim, num_kv_heads; + int embed_dim, num_q_heads, k_dim, v_dim, num_kv_heads, + tensor_parallelism_degree; float dropout, scaling_factor; bool qkv_bias, final_bias, add_zero_attn, apply_rotary_embedding, scaling_query, qk_prod_scaling, position_bias, streaming_cache; @@ -2938,6 +2940,7 @@ void FFModel::deserialize_graph_optimal_view( dez.deserialize(position_bias); dez.deserialize(streaming_cache); dez.deserialize(num_kv_heads); + dez.deserialize(tensor_parallelism_degree); size_t name_len; char name[MAX_OPNAME] = {0}; dez.deserialize(name_len); @@ -2960,6 +2963,7 @@ void FFModel::deserialize_graph_optimal_view( params.position_bias = position_bias; params.streaming_cache = streaming_cache; params.num_kv_heads = num_kv_heads; + params.tensor_parallelism_degree = tensor_parallelism_degree; strcpy(params.name, name); node = get_or_create_node(inputs[0], params); @@ -3223,21 +3227,21 @@ void FFModel::deserialize_graph_optimal_view( optimal_views[guid_to_nodes[guid]] = view; } assert(dez.get_remaining_bytes() == 0); - printf("Deserialized Views...\n"); - for (auto const &it : optimal_views) { - printf("node[%zu]: type(%s) view(%d %d %d) ", - it.first.guid, - it.first.to_string().c_str(), - it.second.ndims, - it.second.dim[0], - it.second.start_device_id); - auto const &list = graph->inEdges.at(it.first); - for (auto const &it2 : list) { - Edge e = it2; - printf(" inEdge(node(%zu) idx(%d))", e.srcOp.guid, e.srcIdx); - } - printf("\n"); - } + // printf("Deserialized Views...\n"); + // for (auto const &it : optimal_views) { + // printf("node[%zu]: type(%s) view(%d %d %d) ", + // it.first.guid, + // it.first.to_string().c_str(), + // it.second.ndims, + // it.second.dim[0], + // it.second.start_device_id); + // auto const &list = graph->inEdges.at(it.first); + // for (auto const &it2 : list) { + // Edge e = it2; + // printf(" inEdge(node(%zu) idx(%d))", e.srcOp.guid, e.srcIdx); + // } + // printf("\n"); + // } } }; // namespace FlexFlow diff --git a/src/runtime/inference_manager.cc b/src/runtime/inference_manager.cc index dd13bb2e05..864af656c4 100644 --- a/src/runtime/inference_manager.cc +++ b/src/runtime/inference_manager.cc @@ -238,41 +238,41 @@ void InferenceManager::compile_model_and_allocate_buffer(FFModel *model, } // print optimized graph - for (size_t i = 0; i < model->operators.size(); i++) { - Op *op = model->operators[i]; - if (op->op_type == OP_INPUT || op->op_type == OP_WEIGHT) { - continue; - } - printf("operator[%zu]: type(%s) guid(%lu)\n", - i, - get_operator_type_name(model->operators[i]->op_type).c_str(), - model->operators[i]->op_guid); - for (int j = 0; j < op->numInputs; j++) { - assert(tensor_buffer.find(op->inputs[j]) != tensor_buffer.end()); - LogicalRegion handle = tensor_buffer[op->inputs[j]][0]->region; - printf("\tinputs[%d] mapped_region(%d,%d,%d)\n", - j, - handle.get_index_space().get_id(), - handle.get_field_space().get_id(), - handle.get_tree_id()); - } - for (int j = 0; j < op->numOutputs; j++) { - LogicalRegion handle = tensor_buffer[op->outputs[j]][0]->region; - printf("\toutputs[%d] mapped_region(%d,%d,%d)\n", - j, - handle.get_index_space().get_id(), - handle.get_field_space().get_id(), - handle.get_tree_id()); - } - for (int j = 0; j < op->numWeights; j++) { - LogicalRegion handle = op->weights[j]->region; - printf("\tweights[%d] mapped_region(%d,%d,%d)\n", - j, - handle.get_index_space().get_id(), - handle.get_field_space().get_id(), - handle.get_tree_id()); - } - } + // for (size_t i = 0; i < model->operators.size(); i++) { + // Op *op = model->operators[i]; + // if (op->op_type == OP_INPUT || op->op_type == OP_WEIGHT) { + // continue; + // } + // printf("operator[%zu]: type(%s) guid(%lu)\n", + // i, + // get_operator_type_name(model->operators[i]->op_type).c_str(), + // model->operators[i]->op_guid); + // for (int j = 0; j < op->numInputs; j++) { + // assert(tensor_buffer.find(op->inputs[j]) != tensor_buffer.end()); + // LogicalRegion handle = tensor_buffer[op->inputs[j]][0]->region; + // printf("\tinputs[%d] mapped_region(%d,%d,%d)\n", + // j, + // handle.get_index_space().get_id(), + // handle.get_field_space().get_id(), + // handle.get_tree_id()); + // } + // for (int j = 0; j < op->numOutputs; j++) { + // LogicalRegion handle = tensor_buffer[op->outputs[j]][0]->region; + // printf("\toutputs[%d] mapped_region(%d,%d,%d)\n", + // j, + // handle.get_index_space().get_id(), + // handle.get_field_space().get_id(), + // handle.get_tree_id()); + // } + // for (int j = 0; j < op->numWeights; j++) { + // LogicalRegion handle = op->weights[j]->region; + // printf("\tweights[%d] mapped_region(%d,%d,%d)\n", + // j, + // handle.get_index_space().get_id(), + // handle.get_field_space().get_id(), + // handle.get_tree_id()); + // } + // } } void InferenceManager::init_operators_inference(FFModel *model) { @@ -525,7 +525,7 @@ void FFModel::compile_inference() { deserialize_graph_optimal_view(dez, best_graph, optimal_views); operators.clear(); convert_graph_to_operators(best_graph, optimal_views); - best_graph->print_dot(); + // best_graph->print_dot(); delete best_graph; for (auto const &layer : layers) { // map inputs to parallel tensor diff --git a/src/runtime/memory_allocator.cc b/src/runtime/memory_allocator.cc index 06a7c468a4..46bef18c8c 100644 --- a/src/runtime/memory_allocator.cc +++ b/src/runtime/memory_allocator.cc @@ -14,6 +14,7 @@ */ #include "flexflow/utils/memory_allocator.h" +#include "flexflow/mapper.h" namespace FlexFlow { @@ -21,14 +22,30 @@ namespace FlexFlow { using Legion::coord_t; using Legion::Memory; using Realm::RegionInstance; +using namespace Legion; +using namespace Mapping; + +Legion::Logger log_ff_mem_allocator("MemoryAllocator"); MemoryAllocator::MemoryAllocator(Memory _memory) : memory(_memory), reserved_ptr(nullptr), instance_ptr(nullptr), reserved_total_size(0), reserved_allocated_size(0), - instance_total_size(0), instance_allocated_size(0) {} + instance_total_size(0), instance_allocated_size(0), + log_instance_creation(false) { + InputArgs const &command_args = HighLevelRuntime::get_input_args(); + char **argv = command_args.argv; + int argc = command_args.argc; + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--log-instance-creation")) { + log_instance_creation = true; + break; + } + } +} void MemoryAllocator::create_legion_instance(RegionInstance &inst, - size_t size) { + size_t size, + char const *task_name) { // Assert that we have used up previously created region instance assert(instance_total_size == instance_allocated_size); Realm::Rect<1, coord_t> bounds(Realm::Point<1, coord_t>(0), @@ -38,6 +55,16 @@ void MemoryAllocator::create_legion_instance(RegionInstance &inst, Realm::RegionInstance::create_instance( inst, memory, bounds, field_sizes, 0, Realm::ProfilingRequestSet()) .wait(); + if (log_instance_creation) { + log_ff_mem_allocator.print( + "Created instance in memory_kind: %s memory_id: %llx size: %zu " + "(capacity %lu) task_name: %s", + Legion::Mapping::Utilities::to_string(memory.kind()), + memory.id, + size, + memory.capacity(), + ((task_name != NULL) ? task_name : "unknown")); + } instance_ptr = inst.pointer_untyped(0, 0); instance_total_size = size; instance_allocated_size = 0; diff --git a/src/runtime/model.cc b/src/runtime/model.cc index f48fab25bd..2a72029c59 100644 --- a/src/runtime/model.cc +++ b/src/runtime/model.cc @@ -3393,6 +3393,7 @@ void FFModel::create_operators_from_layers() { config.tensor_parallelism_degree > 1 && (l->op_type == OP_INC_MULTIHEAD_SELF_ATTENTION || l->op_type == OP_TREE_INC_MULTIHEAD_SELF_ATTENTION || + l->op_type == OP_SPEC_INC_MULTIHEAD_SELF_ATTENTION || // mlp layer is_mlp_block(layer_idx) || // llama mlp layer @@ -4106,6 +4107,7 @@ struct DefaultConfig { static int const epochs = 1; // const static int iterations = 1; static int const batchSize = 64; + static bool const log_instance_creation = false; static bool const profiling = false; static bool const benchmarking = false; static bool const inference_debugging = false; @@ -4143,6 +4145,7 @@ FFConfig::FFConfig() { // iterations = DefaultConfig::iterations; batchSize = DefaultConfig::batchSize; profiling = DefaultConfig::profiling; + log_instance_creation = DefaultConfig::log_instance_creation; benchmarking = DefaultConfig::benchmarking; inference_debugging = DefaultConfig::inference_debugging; learningRate = DefaultConfig::learningRate; @@ -4330,6 +4333,10 @@ void FFConfig::parse_args(char **argv, int argc) { cpusPerNode = atoi(argv[++i]); continue; } + if ((!strcmp(argv[i], "--log-instance-creation"))) { + log_instance_creation = true; + continue; + } if (!strcmp(argv[i], "--profiling")) { profiling = true; continue; @@ -4534,47 +4541,16 @@ void register_flexflow_internal_tasks(Runtime *runtime, } } { - TaskVariantRegistrar registrar(LOAD_FLOAT_WEIGHT_TASK_ID, - "load_float_weight_task"); + TaskVariantRegistrar registrar(LOAD_WEIGHT_TASK_ID, "load_weight_task"); registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC)); if (pre_register) { - Runtime::preregister_task_variant( - registrar, "load_float_weight_task"); + Runtime::preregister_task_variant( + registrar, "load_weight_task"); } else { if (enable_control_replication) { registrar.global_registration = false; } - runtime->register_task_variant( - registrar); - } - } - { - TaskVariantRegistrar registrar(LOAD_HALF_WEIGHT_TASK_ID, - "load_half_weight_task"); - registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC)); - if (pre_register) { - Runtime::preregister_task_variant( - registrar, "load_half_weight_task"); - } else { - if (enable_control_replication) { - registrar.global_registration = false; - } - runtime->register_task_variant( - registrar); - } - } - { - TaskVariantRegistrar registrar(LOAD_QUANT_WEIGHT_TASK_ID, - "load_quant_weight_task"); - registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC)); - if (pre_register) { - Runtime::preregister_task_variant( - registrar, "load_quant_weight_task"); - } else { - if (enable_control_replication) { - registrar.global_registration = false; - } - runtime->register_task_variant( + runtime->register_task_variant( registrar); } } @@ -6476,7 +6452,6 @@ void register_flexflow_internal_tasks(Runtime *runtime, TaskVariantRegistrar registrar(FUSEDOP_INIT_TASK_ID, "FusedOp Init"); registrar.add_constraint(ProcessorConstraint(Processor::TOC_PROC)); registrar.set_leaf(); - registrar.set_concurrent(); if (pre_register) { Runtime::preregister_task_variant( registrar, "FusedOp Init Task"); @@ -6715,7 +6690,6 @@ void register_flexflow_internal_tasks(Runtime *runtime, TaskVariantRegistrar registrar(ALLREDUCE_INIT_TASK_ID, "AllReduce Init"); registrar.add_constraint(ProcessorConstraint(Processor::TOC_PROC)); registrar.set_leaf(); - registrar.set_concurrent(); if (pre_register) { Runtime::preregister_task_variant( registrar, "AllReduce init Task"); @@ -6767,7 +6741,6 @@ void register_flexflow_internal_tasks(Runtime *runtime, registrar.set_leaf(); // AllReduce forward and backward must run concurrentluy since they // use ncclAllReduce internally - registrar.set_concurrent(); if (pre_register) { Runtime::preregister_task_variant( registrar, "AllReduce Backward Task"); diff --git a/src/runtime/optimizer_kernel.cpp b/src/runtime/optimizer_kernel.cpp index 59efaf5256..a33ee35de7 100644 --- a/src/runtime/optimizer_kernel.cpp +++ b/src/runtime/optimizer_kernel.cpp @@ -86,7 +86,9 @@ __host__ void SGDOptimizer::ps_update_task_gpu(SGDOptimizer const *op, } #ifdef FF_USE_NCCL -__host__ void SGDOptimizer::nccl_update_task_gpu(SGDOptimizer const *op, +__host__ void SGDOptimizer::nccl_update_task_gpu(Legion::Context ctx, + Legion::Runtime *runtime, + SGDOptimizer const *op, OpMeta const *meta, float const *w_grad_ptr, size_t size, @@ -96,6 +98,7 @@ __host__ void SGDOptimizer::nccl_update_task_gpu(SGDOptimizer const *op, // fprintf(stderr, "weight(%p) Before ncclAllReduce...\n", w_grad_ptr); hipStream_t stream; checkCUDA(get_legion_stream(&stream)); + runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllReduce(w_grad_ptr, (float *)w_grad_ptr, size, @@ -103,6 +106,7 @@ __host__ void SGDOptimizer::nccl_update_task_gpu(SGDOptimizer const *op, ncclSum, meta->handle.ncclComm, stream)); + runtime->concurrent_task_barrier(ctx); // fprintf(stderr, "weight(%p) After ncclAllReduce...\n", w_grad_ptr); // Step 2: SGD update @@ -208,7 +212,9 @@ __host__ void AdamOptimizer::ps_update_task_gpu(AdamOptimizer const *op, } #ifdef FF_USE_NCCL -__host__ void AdamOptimizer::nccl_update_task_gpu(AdamOptimizer const *op, +__host__ void AdamOptimizer::nccl_update_task_gpu(Legion::Context ctx, + Legion::Runtime *runtime, + AdamOptimizer const *op, OpMeta const *meta, float const *w_grad_ptr, size_t size, @@ -218,6 +224,7 @@ __host__ void AdamOptimizer::nccl_update_task_gpu(AdamOptimizer const *op, // Use NCCL to sync gradients hipStream_t stream; checkCUDA(get_legion_stream(&stream)); + runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllReduce(w_grad_ptr, (float *)w_grad_ptr, size, @@ -225,6 +232,7 @@ __host__ void AdamOptimizer::nccl_update_task_gpu(AdamOptimizer const *op, ncclSum, meta->handle.ncclComm, stream)); + runtime->concurrent_task_barrier(ctx); // fprintf(stderr, "alpha = %.8lf alpha_t = %.8lf decay = %.8lf\n", // op->alpha, op->alpha_t, op->weight_decay); // Step 2: Adam update diff --git a/src/runtime/optimizer_kernel.cu b/src/runtime/optimizer_kernel.cu index 72ee74940f..6bc3d52b24 100644 --- a/src/runtime/optimizer_kernel.cu +++ b/src/runtime/optimizer_kernel.cu @@ -75,8 +75,8 @@ __host__ void SGDOptimizer::ps_update_task_gpu(SGDOptimizer const *op, } #ifdef FF_USE_NCCL -__host__ void SGDOptimizer::nccl_update_task_gpu(Context ctx, - Runtime *runtime, +__host__ void SGDOptimizer::nccl_update_task_gpu(Legion::Context ctx, + Legion::Runtime *runtime, SGDOptimizer const *op, OpMeta const *meta, float const *w_grad_ptr, @@ -187,8 +187,8 @@ __host__ void AdamOptimizer::ps_update_task_gpu(AdamOptimizer const *op, } #ifdef FF_USE_NCCL -__host__ void AdamOptimizer::nccl_update_task_gpu(Context ctx, - Runtime *runtime, +__host__ void AdamOptimizer::nccl_update_task_gpu(Legion::Context ctx, + Legion::Runtime *runtime, AdamOptimizer const *op, OpMeta const *meta, float const *w_grad_ptr, diff --git a/src/runtime/parallel_tensor.cc b/src/runtime/parallel_tensor.cc index 8f1be15fd1..202983e8f0 100644 --- a/src/runtime/parallel_tensor.cc +++ b/src/runtime/parallel_tensor.cc @@ -1,4 +1,5 @@ #include "flexflow/ffconst_utils.h" +#include "flexflow/mapper.h" #include "flexflow/model.h" #include "flexflow/ops/attention.h" #include "flexflow/ops/concat.h" @@ -19,6 +20,9 @@ namespace FlexFlow { using namespace Legion; +using namespace Legion; +using namespace Mapping; +Legion::Logger pt_logger("ParallelTensor"); TensorBase::TensorBase(TensorBase const &rhs) { tensor_guid = rhs.tensor_guid; @@ -647,11 +651,41 @@ bool ParallelTensorBase::is_valid_machine_view(MachineView const &view) const { return true; } +size_t get_physical_region_size(PhysicalRegion const &pr, + Context ctx, + Runtime *runtime) { + // Get the logical region + LogicalRegion lr = pr.get_logical_region(); + + // Get the index space domain + Domain domain = runtime->get_index_space_domain(ctx, lr.get_index_space()); + + // Get number of elements in the domain + size_t num_elements = domain.get_volume(); + + // Get the field space + FieldSpace fs = lr.get_field_space(); + + // Get all fields in the field space + std::vector fields; + runtime->get_field_space_fields(ctx, fs, fields); + + // Sum up the size of all fields + size_t total_field_size = 0; + for (FieldID fid : fields) { + size_t field_size = runtime->get_field_size(ctx, fs, fid); + total_field_size += field_size; + } + + // Total size is number of elements times size of each element + return num_elements * total_field_size; +} + template bool ParallelTensorBase::set_tensor(FFModel const *ff, std::vector const &dim_sizes, T const *data) { - Context ctx = ff->config.lg_ctx; + Context ctx = Legion::Runtime::get_context(); Runtime *runtime = ff->config.lg_hlr; // TODO: check data type matches // TODO: Currently we use a task launch, change to index launch for NCCL @@ -678,6 +712,28 @@ bool ParallelTensorBase::set_tensor(FFModel const *ff, InlineLauncher launcher(req); PhysicalRegion pr = runtime->map_region(ctx, launcher); pr.wait_until_valid(); + + if (ff->config.log_instance_creation) { + size_t pr_size = get_physical_region_size(pr, ctx, runtime); + if (pr_size != volume * num_replicas * sizeof(T)) { + std::cout << "Physical region size: " << pr_size << std::endl; + std::cout << "Volume: " << volume << std::endl; + std::cout << "Num replicas: " << num_replicas << std::endl; + std::cout << "Size of T: " << sizeof(T) << std::endl; + } + assert(pr_size == volume * num_replicas * sizeof(T)); + std::set memories; + pr.get_memories(memories); + assert(memories.size() == 1); + Memory memory = *(memories.begin()); + pt_logger.print("Created instance in memory_kind: %s memory_id: %llx size: " + "%zu (capacity %lu) task_name: set_tensor", + Legion::Mapping::Utilities::to_string(memory.kind()), + memory.id, + pr_size, + memory.capacity()); + } + switch (num_dims) { #define DIMFUNC(DIM) \ case DIM: { \ @@ -704,7 +760,7 @@ template bool ParallelTensorBase::get_tensor(FFModel const *ff, T *data, bool get_gradients) { - Context ctx = ff->config.lg_ctx; + Context ctx = Legion::Runtime::get_context(); Runtime *runtime = ff->config.lg_hlr; LogicalRegion weight_lr = LogicalRegion::NO_REGION; if (sync_type == ParameterSyncType::PS) { diff --git a/src/runtime/request_manager.cc b/src/runtime/request_manager.cc index 55ee6ea5e2..734855fa59 100644 --- a/src/runtime/request_manager.cc +++ b/src/runtime/request_manager.cc @@ -35,6 +35,7 @@ namespace FlexFlow { using namespace Legion; using tokenizers::Tokenizer; +using RequestGuid = BatchConfig::RequestGuid; Legion::Logger log_req_mgr("RequestManager"); @@ -263,6 +264,19 @@ void RequestManager::set_max_tree_width(int max_tree_width) { } } +int RequestManager::get_expansion_degree() { + assert(expansion_degree > 0 and + expansion_degree <= BatchConfig::MAX_TREE_WIDTH and + "Invalid expansion_degree"); + return expansion_degree; +} +void RequestManager::set_expansion_degree(int expansion_degree_) { + assert(expansion_degree > 0 and + expansion_degree <= BatchConfig::MAX_TREE_WIDTH and + "Invalid expansion_degree"); + this->expansion_degree = expansion_degree_; +} + void RequestManager::set_speculative_sampling(bool speculative_sampling_) { speculative_sampling = speculative_sampling_; } @@ -350,6 +364,8 @@ double RequestManager::get_request_expected_latency(Request &request) { } Request &RequestManager::get_request_with_guid(RequestGuid guid) { + assert(all_requests.find(guid) != all_requests.end() && + "Request with the given GUID does not exist."); return all_requests[guid]; } @@ -384,11 +400,11 @@ bool RequestManager::SharedTokenTreeNodePtrDoubleRequestGuidLess ::operator()( void RequestManager::register_tokenizer(ModelType type, int bos_token_id, - int eos_token_id, + std::vector eos_token_ids, std::string const &path) { this->model_type = type; this->bos_token_id = bos_token_id; - this->eos_token_id = eos_token_id; + this->eos_token_ids = eos_token_ids; std::filesystem::path tokenizer_folder(path); if (model_type == ModelType::LLAMA) { @@ -472,6 +488,7 @@ size_t RequestManager::get_num_ssms() { return ssm_models.size(); } + RequestManager::RequestGuid RequestManager::register_new_request(GenerationRequest const &req) { // Add a new request @@ -484,19 +501,19 @@ RequestManager::RequestGuid request.tokens.push_back(bos_token_id); } std::vector tokens = this->tokenizer_->Encode(req.prompt); - for (int i = 0; i < tokens.size(); i++) { - std::cout << "[" << i << "]" << tokens.at(i) << "\n"; - } - std::cout << "[slo ratio] " << req.slo_ratio << std::endl; + // for (int i = 0; i < tokens.size(); i++) { + // std::cout << "[" << i << "]" << tokens.at(i) << "\n"; + // } + // std::cout << "[slo ratio] " << req.slo_ratio << std::endl; request.tokens.insert(request.tokens.end(), tokens.begin(), tokens.end()); request.set_slo_ratio(req.slo_ratio); if (get_num_ssms() == 0) { - std::cout << "No small speculative model registered, using incremental " - "decoding." - << std::endl; + // std::cout << "No small speculative model registered, using incremental " + // "decoding." + // << std::endl; } else { - std::cout << "Num of SSMs: " << get_num_ssms() << std::endl; + // std::cout << "Num of SSMs: " << get_num_ssms() << std::endl; assert(get_num_ssms() == 1 && "Only one SSM is supported now."); init_token_tree(request.guid); } @@ -515,6 +532,15 @@ RequestManager::RequestGuid gr.slo_ratio = req.slo_ratio; gr.emission_time_ms = req.emission_time_ms; + // Record time when request was enqueued + // Step idx -2: enqueueing; step idx -1: prefilling begins, step idx 0: + // prefilling finished + NewProfileInfo new_profile_info; + new_profile_info.timestamp = Realm::Clock::current_time_in_microseconds(); + new_profile_info.request_guid = request.guid; + new_profile_info.request_step_idx = -2; + new_profiling_info.push_back(new_profile_info); + { std::lock_guard const lock(request_queue_mutex); pending_request_queue.push(request); @@ -531,13 +557,13 @@ RequestManager::RequestGuid } { - std::string output = "New request tokens:"; - output = "[" + std::to_string(request.guid) + "] " + output; - for (int i = 0; i < request.tokens.size(); i++) { - output = output + " " + std::to_string(request.tokens[i]); - } - log_req_mgr.print("%s", output.c_str()); - write_to_output_file("", output); + // std::string output = "New request tokens:"; + // output = "[" + std::to_string(request.guid) + "] " + output; + // for (int i = 0; i < request.tokens.size(); i++) { + // output = output + " " + std::to_string(request.tokens[i]); + // } + // log_req_mgr.print("%s", output.c_str()); + // write_to_output_file("", output); } return request.guid; @@ -580,6 +606,24 @@ int RequestManager::get_empty_request_index() { return -1; } +std::unordered_map + RequestManager::get_requests_profiling() { + return profiling_requests; +} + +std::unordered_map + RequestManager::get_request_generation_results() { + return request_generation_results; +} + +ProfileInfo RequestManager::get_profiling_info() { + return profiling; +} + +std::vector RequestManager::get_new_profiling_info() { + return new_profiling_info; +} + BatchConfigFuture RequestManager::get_next_batch_config( InferenceResultFuture const &result, Context ctx, Runtime *runtime) { RequestManager *rm = this; @@ -682,6 +726,20 @@ void RequestManager::request_update_attainment(int batch_index, bool attained) { request.attained &= attained; } +bool isPrefixAndRemove(std::vector const &prefix, std::vector &vec) { + if (prefix.size() > vec.size()) { + return false; + } + + if (std::equal(prefix.begin(), prefix.end(), vec.begin())) { + vec.erase(vec.begin(), vec.begin() + prefix.size()); + return true; + } + + return false; +} + + void RequestManager::request_complete_clean_up(int batch_index) { RequestGuid guid = guid_of_requests[batch_index]; profiling_requests[guid].finish_time = @@ -694,35 +752,48 @@ void RequestManager::request_complete_clean_up(int batch_index) { request.status = Request::COMPLETED; // Find the sos and eos in the sequence - auto bos_it = std::find( - request.tokens.begin(), request.tokens.end(), this->bos_token_id); - auto eos_rit = std::find( - request.tokens.rbegin(), request.tokens.rend(), this->eos_token_id); - std::vector::iterator eos_it; - if (eos_rit != request.tokens.rend()) { - eos_it = eos_rit.base(); - } else { - eos_it = request.tokens.end(); - } + // auto bos_it = std::find( + // request.tokens.begin(), request.tokens.end(), this->bos_token_id); + // auto eos_rit = std::find( + // request.tokens.rbegin(), request.tokens.rend(), this->eos_token_id); + // std::vector::iterator eos_it; + // if (eos_rit != request.tokens.rend()) { + // eos_it = eos_rit.base(); + // } else { + // eos_it = request.tokens.end(); + // } // std::string output = // this->tokenizer_->Decode(std::vector(bos_it, eos_it)); std::string output = this->tokenizer_->Decode(request.tokens); { std::lock_guard const lock(request_result_mutex); - request_generation_results[guid].output_text = output; - request_generation_results[guid].output_tokens = - std::vector(bos_it, eos_it); + request_generation_results[guid].output_tokens = request.tokens; + assert(isPrefixAndRemove(request_generation_results[guid].input_tokens, + request_generation_results[guid].output_tokens)); + if (request_generation_results[guid].output_tokens.size() > 0 && + is_eos_token( + request_generation_results[guid].output_tokens + [request_generation_results[guid].output_tokens.size() - 1]) && + !request.add_special_tokens) { + request_generation_results[guid].output_tokens.pop_back(); + } + request_generation_results[guid].output_text = this->tokenizer_->Decode( + request_generation_results[guid].output_tokens); + request_generation_results[guid].decoding_steps = + profiling_requests[guid].llm_decoding_steps; + // request_generation_results[guid].output_tokens = + // std::vector(bos_it, eos_it); } trigger_request_completion_future(guid); - std::cout << "Request " << guid << " completed: " << std::endl << std::endl; - std::cout << "" << output; - if (eos_rit != request.tokens.rend()) { - std::cout << ""; - } - std::cout << std::endl << std::endl; + std::cout << "Request " << guid << " completed" << std::endl; + // std::cout << "" << output; + // if (eos_rit != request.tokens.rend()) { + // std::cout << ""; + // } + // std::cout << std::endl << std::endl; { RequestProfileInfo profile_info = profiling_requests[guid]; @@ -756,7 +827,8 @@ void RequestManager::request_complete_clean_up(int batch_index) { *os << "SSM decoding steps: " << profile_info.ssm_decoding_steps << std::endl; } - *os << output << std::endl << std::endl; + *os << std::endl; + // *os << output << std::endl << std::endl; if (!output_filepath.empty()) { output_file.close(); @@ -934,23 +1006,23 @@ bool RequestManager::update_llm_prefill_results(InferenceResult const &result) { request->tokens.push_back( result.token_ids[num_tokens + request->num_tokens_in_batch - 1]); - if (request->tokens.back() == eos_token_id) { + if (is_eos_token(request->tokens.back())) { request_complete_clean_up(request->batch_index); } else { // Temporarily offload request from the batch request_offload_from_batch(request->batch_index); prefilled_requests.push(request); - } - if (decoding_mode == SPECULATIVE_DECODING) { - // Add the last token to the token tree - assert(request->committed_tokens.empty() && - "The committed tokens should be empty."); - request->committed_tokens.push_back(Request::CommittedToken{ - -1, (int)request->tokens.size() - 1, request->tokens.back()}); - init_token_tree(request->guid); - add_root_to_spec_token_tree(request->guid, request->tokens.back()); - update_bitmask_prompt(request->guid, 1); + if (decoding_mode == SPECULATIVE_DECODING) { + // Add the last token to the token tree + assert(request->committed_tokens.empty() && + "The committed tokens should be empty."); + request->committed_tokens.push_back(Request::CommittedToken{ + -1, (int)request->tokens.size() - 1, request->tokens.back()}); + init_token_tree(request->guid); + add_root_to_spec_token_tree(request->guid, request->tokens.back()); + update_bitmask_prompt(request->guid, 1); + } } } else { // Next phase will still be prefilling @@ -999,7 +1071,16 @@ bool RequestManager::update_llm_decode_results(InferenceResult const &result) { request.decode_latency_ms <= get_request_expected_latency(request); profiling_requests[guid].llm_decoding_steps++; nb_requests_decoded++; - if (request.tokens.back() == eos_token_id or + + NewProfileInfo new_profile_info; + new_profile_info.timestamp = Realm::Clock::current_time_in_microseconds(); + new_profile_info.request_guid = guid; + new_profile_info.request_step_idx = + profiling_requests[guid].llm_decoding_steps - 1; + new_profile_info.num_generated_tokens = 1; + new_profiling_info.push_back(new_profile_info); + + if (is_eos_token(request.tokens.back()) or request.decode_length() >= get_max_output_length() or request.tokens.size() >= get_max_sequence_length()) { request_update_attainment(request_index, attained); @@ -1148,6 +1229,18 @@ BatchConfig RequestManager::prepare_llm_prefilling_batch() { if (num_tokens_in_batch > 0) { bc.num_available_requests++; } + + // Record prefilling start time. We don't do this for speculative decoding, + // because in that case we start the timer in the ssm prefilling Step idx + // -2: enqueueing; step idx -1: prefilling begins, step idx 0: prefilling + // finished + if (decoding_mode == INCREMENTAL_DECODING) { + NewProfileInfo new_profile_info; + new_profile_info.timestamp = Realm::Clock::current_time_in_microseconds(); + new_profile_info.request_guid = request->guid; + new_profile_info.request_step_idx = -1; + new_profiling_info.push_back(new_profile_info); + } } bc.num_tokens = num_tokens; @@ -1212,6 +1305,15 @@ BatchConfig RequestManager::prepare_ssm_prefilling_batch() { if (num_tokens_in_batch > 0) { bc.num_available_requests++; } + + // Record prefilling start time + // Step idx -2: enqueueing; step idx -1: prefilling begins, step idx 0: + // prefilling finished + NewProfileInfo new_profile_info; + new_profile_info.timestamp = Realm::Clock::current_time_in_microseconds(); + new_profile_info.request_guid = request->guid; + new_profile_info.request_step_idx = -1; + new_profiling_info.push_back(new_profile_info); } bc.num_tokens = num_tokens; @@ -1580,6 +1682,12 @@ BatchConfig RequestManager::prepare_verify_batch_config() { } layer_index++; } + if (verbose) { + // print token tree + std::cout << "Token tree for request " << request_index << ": " + << std::endl; + std::cout << token_tree << std::endl; + } new_bc.requestsInfo[request_index].num_tokens_in_batch = token_tree_index; request.first_token_offset_in_batch = new_bc.num_tokens - token_tree_index; @@ -1601,6 +1709,23 @@ BatchConfig RequestManager::prepare_verify_batch_config() { return new_bc; } +int get_tree_size(Request const &request) { + int size = 0; + for (auto &layer : request.speculative_token_trees[0].tree_layers) { + size += (int)layer.size(); + } + return size; +} + +bool RequestManager::is_eos_token(TokenId token_id) { + for (int eos_token : eos_token_ids) { + if (token_id == eos_token) { + return true; + } + } + return false; +} + bool RequestManager::update_llm_verify_results( InferenceResult const &llm_verify_result) { // We may have two types of InferenceResults, one is the results from @@ -1684,7 +1809,7 @@ bool RequestManager::update_llm_verify_results( // metainfo stored in the RequestManager. Otherwise, update its bitmask. bool eos_token_found = false; for (auto const &committed_token : request.committed_tokens) { - if (committed_token.token_id == eos_token_id) { + if (is_eos_token(committed_token.token_id)) { eos_token_found = true; break; } @@ -1751,6 +1876,14 @@ bool RequestManager::update_ssm_inference_results( append_bitmask(guid); profiling_requests[guid].ssm_decoding_steps++; + + if (current_ssm_step == ssm_tree_depth) { + assert(profiling_requests[guid].ssm_decoding_steps % ssm_tree_depth == 0); + profiling_requests[guid].speculation_start_timestamp = + profiling.ssm_step_start; + profiling_requests[guid].speculation_end_timestamp = + Realm::Clock::current_time_in_microseconds(); + } } // Stop conditions @@ -2121,7 +2254,7 @@ void RequestManager::get_verify_results_sample( } std::cout << std::endl; std::string output = this->tokenizer_->Decode(request.tokens); - std::cout << "Output sequence: " << output << std::endl; + // std::cout << "Output sequence: " << output << std::endl; } } } @@ -2160,6 +2293,7 @@ void RequestManager::get_verify_results_greedy( int current_token_index = 1; // Because we skip the root // We skip the first layer + bool found_eos = false; for (auto layer_it = token_tree.tree_layers.begin() + 1; layer_it != token_tree.tree_layers.end(); ++layer_it) { @@ -2202,31 +2336,68 @@ void RequestManager::get_verify_results_greedy( last_accepted_token_index = current_token_index; last_accepted_token_index_in_layer = current_token_index_in_layer; committed_token_index++; + if (is_eos_token(node_ptr->id)) { + found_eos = true; + } } current_token_index++; current_token_index_in_layer++; } + if (found_eos) { + break; + } } if (!token_accepted_this_layer) { // No token is accepted in this layer, we should stop the traversal break; } + if (found_eos) { + break; + } } // Add the last token (that is not verified by the LLM) // from_index: since this token is not in the token tree, the llm // doesn't have its KV cache, so the from_index should be a place // holder, which is -1 - request.committed_tokens.push_back(Request::CommittedToken( - -1, - committed_token_index, - llm_verify_result - .token_ids[llm_result_offset + last_accepted_token_index])); - request.tokens.push_back( - llm_verify_result - .token_ids[llm_result_offset + last_accepted_token_index]); + if (!found_eos) { + request.committed_tokens.push_back(Request::CommittedToken( + -1, + committed_token_index, + llm_verify_result + .token_ids[llm_result_offset + last_accepted_token_index])); + request.tokens.push_back( + llm_verify_result + .token_ids[llm_result_offset + last_accepted_token_index]); + } + + assert(request.committed_tokens.size() >= 2); + int nb_generated_tokens = (int)request.committed_tokens.size() - + 1; // exclude previous bonus token + int accepted_tokens = (int)request.committed_tokens.size() - + 1; // exclude previous bonus token + if (!found_eos) { + accepted_tokens--; // exclude the last bonus token (if we found eos, we + // don't add it) + } + total_nb_generated_tokens += nb_generated_tokens; + + NewProfileInfo new_profile_info; + new_profile_info.timestamp = Realm::Clock::current_time_in_microseconds(); + new_profile_info.request_guid = guid; + new_profile_info.request_step_idx = + profiling_requests[guid].llm_decoding_steps - + 1; // check if this has already been incremented + new_profile_info.num_speculated_tokens = get_tree_size(request); + new_profile_info.num_accepted_tokens = accepted_tokens; + new_profile_info.speculation_score = -1.0; + new_profile_info.num_generated_tokens = nb_generated_tokens; + new_profile_info.speculation_start_timestamp = + profiling_requests[guid].speculation_start_timestamp; + new_profile_info.speculation_end_timestamp = + profiling_requests[guid].speculation_end_timestamp; + new_profiling_info.push_back(new_profile_info); - total_nb_generated_tokens += request.committed_tokens.size() - 1; if (verbose) { std::cout << "Request " << request.guid << " committed tokens: "; for (auto const &committed_token : request.committed_tokens) { @@ -2255,10 +2426,10 @@ std::vector for (size_t i = 0; i < requests.size(); i++) { requests[i].slo_ratio = emission_machine.sample_slo_ratio(); requests[i].emission_time_ms = emission_machine.get_elapsed_time_ms(); - printf("Prompt[%ld] with slo %.3f: %s\n", - i, - requests[i].slo_ratio, - requests[i].prompt.c_str()); + // printf("Prompt[%ld] with slo %.3f: %s\n", + // i, + // requests[i].slo_ratio, + // requests[i].prompt.c_str()); RequestManager::RequestGuid guid = rm->register_new_request(requests[i]); if (guid != RequestManager::INVALID_GUID) { guids.push_back(guid); @@ -2545,8 +2716,9 @@ void RequestManager::terminate_background_server() { // Write the last profiling statistics to output file std::string str = "[Profiling Statistics]"; - long long total_time = Realm::Clock::current_time_in_microseconds() - - profiling.server_start_time; + profiling.server_end_time = Realm::Clock::current_time_in_microseconds(); + long long total_time = + profiling.server_end_time - profiling.server_start_time; int total_requests = 0; for (auto const &profiling_info : profiling_requests) { int request_id = profiling_info.first; @@ -2709,6 +2881,25 @@ void RequestManager::terminate_background_server() { goodput_str += ")"; str += goodput_str; + if (profiling_requests.size() != all_requests.size()) { + std::cerr << "profiling_requests.size()=" << profiling_requests.size() + << " != all_requests.size()=" << all_requests.size() + << std::endl; + } + assert(profiling_requests.size() == all_requests.size()); + str += "\nDecoding Steps: "; + for (auto const &profiling_info : profiling_requests) { + int request_id = profiling_info.first; + Request &request = all_requests[request_id]; + str += "Request " + std::to_string(request_id) + ": "; + str += std::to_string(profiling_info.second.llm_decoding_steps); + str += "/"; + str += std::to_string(request.decode_length()); + float speedup = (float)request.decode_length() / + profiling_info.second.llm_decoding_steps; + str += " " + std::to_string(speedup) + "\n"; + } + write_to_output_file("", str); background_server_status = TERMINATED; request_queue_cv.notify_all(); @@ -2854,7 +3045,8 @@ void RequestManager::add_tokens_to_spec_token_tree( void RequestManager::add_tokens_to_spec_token_tree_old_version( InferenceResult const &ssm_inference_result) { - std::vector tree_width_vector = {1, 1, 3, 1, 1, 1, 1, 1}; + std::vector tree_width_vector = { + 1, 1, this->expansion_degree, 1, 1, 1, 1, 1}; int expand_width = tree_width_vector[current_ssm_step - 1]; diff --git a/src/utils/communication_buffer.cu b/src/utils/communication_buffer.cu index cd6cc0db47..83b0385a35 100644 --- a/src/utils/communication_buffer.cu +++ b/src/utils/communication_buffer.cu @@ -23,7 +23,9 @@ // For the i-th pointer, if i is the worker id of the given device, // then the returned i-th ptr_group is the local pointer, // or otherwise it is an peer memory pointer from the remote device. -std::vector create_peer_ptr_group(int num_devices, +std::vector create_peer_ptr_group(Legion::Context ctx, + Legion::Runtime *runtime, + int num_devices, int device_id, ncclComm_t ncclComm, void *allgather_src, @@ -46,12 +48,14 @@ std::vector create_peer_ptr_group(int num_devices, cudaMemcpyHostToDevice, stream)); + runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllGather(allgather_src, allgather_dst, sizeof(void *), ncclChar, ncclComm, stream)); + runtime->concurrent_task_barrier(ctx); std::vector peer_pointers(num_devices); checkCUDA(cudaMemcpyAsync(peer_pointers.data(), @@ -85,7 +89,9 @@ void free_peer_ptr_group(std::vector ptr_group, // all-gathering peer pointers across devices. The size of allgather_src should // be sizeof(void*), and the size of allgather_dst should be sizeof(void*) * // num_devices. -CommunicationBuffer *create_comm_buf_with_local_ptr(int num_devices, +CommunicationBuffer *create_comm_buf_with_local_ptr(Legion::Context ctx, + Legion::Runtime *runtime, + int num_devices, int device_id, ncclComm_t ncclComm, void *allgather_src, @@ -100,21 +106,27 @@ CommunicationBuffer *create_comm_buf_with_local_ptr(int num_devices, comm_buf->num_devices = num_devices; comm_buf->device_id = device_id; comm_buf->local_ptr = local_ptr; - comm_buf->comm_ptrs = create_peer_ptr_group(num_devices, + comm_buf->comm_ptrs = create_peer_ptr_group(ctx, + runtime, + num_devices, device_id, ncclComm, allgather_src, allgather_dst, local_ptr, stream); - comm_buf->barrier_in = create_peer_ptr_group(num_devices, + comm_buf->barrier_in = create_peer_ptr_group(ctx, + runtime, + num_devices, device_id, ncclComm, allgather_src, allgather_dst, barrier_in_ptr, stream); - comm_buf->barrier_out = create_peer_ptr_group(num_devices, + comm_buf->barrier_out = create_peer_ptr_group(ctx, + runtime, + num_devices, device_id, ncclComm, allgather_src, diff --git a/tests/inference/huggingface_inference.py b/tests/inference/huggingface_inference.py index 6857b5cbc1..8fa17f1530 100644 --- a/tests/inference/huggingface_inference.py +++ b/tests/inference/huggingface_inference.py @@ -87,7 +87,7 @@ def main(): # Get Tokenizer hf_config = AutoConfig.from_pretrained(args.model_name, trust_remote_code=True) hf_arch = getattr(hf_config, "architectures")[0] - if hf_arch == "LLaMAForCausalLM" or hf_arch == "LlamaForCausalLM": + if hf_arch == "LLaMAForCausalLM" or hf_arch == "LlamaForCausalLM" or hf_arch == "MistralForCausalLM": tokenizer = LlamaTokenizer.from_pretrained(args.model_name, use_fast=True) else: tokenizer = AutoTokenizer.from_pretrained(args.model_name) From 2990c88332d94872a93ebe7509ffbde13f3ee36b Mon Sep 17 00:00:00 2001 From: Gabriele Oliaro Date: Fri, 15 Nov 2024 17:28:38 +0000 Subject: [PATCH 2/5] cleanup --- benchmarking/average_accepted_tokens.pdf | Bin 15738 -> 15767 bytes benchmarking/benchmark_incr_dec.sh | 4 +- benchmarking/benchmark_specinfer.sh | 2 +- benchmarking/plot_results.ipynb | 176 +++++++++--------- .../queueing_time_vs_arrival_rate.pdf | Bin 18042 -> 18567 bytes benchmarking/throughput_vs_tpot.pdf | Bin 28243 -> 28221 bytes benchmarking/ttft_vs_arrival_rate.pdf | Bin 16898 -> 17427 bytes .../inc_multihead_self_attention_kernels.cu | 8 +- src/parallel_ops/kernels/allreduce_kernels.cu | 2 +- src/runtime/request_manager.cc | 2 - 10 files changed, 96 insertions(+), 98 deletions(-) diff --git a/benchmarking/average_accepted_tokens.pdf b/benchmarking/average_accepted_tokens.pdf index 896519d5d47abe1cf317cf20a46c0599432e6e0f..717e6e68a796d784a518772660ac3d1326e9d1bc 100644 GIT binary patch delta 2378 zcmZuxd0dQn9Bv$8XdP)os);Ttz4tqB5u2T2x>FOiR(A@uQjSqx71k!SW~Meo5kfI( zbWGdj)}>35RFdhWYf)`!r(JB#>-YZiexA?sd4A9L`97cD5I1(eP@bkkH?;Ed^mQ{0 z*voKX0MZW!!4&`uLMQ`c5-SKClm2aH@HA+iWa-8i{;#n)p{-6m6*RxocZ;LzGqYk7 zW?m`4AO zvQYcwhTca9$xGeg7M}!pPZkd>3{|$QtU5)=X`s3mHjaIVOpZ21A8+%@cAjFD|^%e?=hlPE*^Fa+1%GS5NSc9 z>vJ7WESW2R=A_3x-PDh47o`Di8mUR5r_vZIU}XV+N|?SZ9Y>+&NKjvZL<&igil;HTIrl&*+ks*X{m@?6W~_}=TU6iT zaNpE!c&U=AQbNygT=N}u$7MBgrMfp5(w@Hd?j&zhsRUap;UJaZ9El0wSBJ0HZ6D@f#c^|O%YE9lD2kqH9Do&N7qUq1@u-bqz_&o&<7+%Qzu8hztCXr3+E^X%*= z&CG3?W-PmgfFeB;ohWPjxup2-eogJ8`a-*Gt|nP~Y&EEO>uH;+o^LmeAJpyQ7Q6qu zG-O!lD1O)`mzm;GCsFGtF}yY3&pB#-O^$Mqb3*9tP`g!?Rb_c)j`<&S!viZj2iC&{ za<4xn51Qj~Lie2D$n2(%_X5+Fbyp=Nm2tI#b|tM@*4FiBqf=loW=xJ2_@pbEaM*G? zs$BO=RN~L^&hPB&h@Gwe^vo)q#)h{Qan_4cbaD&L+DA+*4e|R5`B@{^Lxu}V_takz z@iwShr004j`ex?3yUEvyla@*{ptdd+Pt9?|F9tu)ea8}VD%f#Nu4|3z7V^!!bk~RSoJLTSvYGRdnU(n+N+3})f{8K(BIWVw=k%)emxggoWz`+fW5Rq|W`@%x7I`kRW!j5i8g9WE$%bA=LT zgKd4$q5;o$MtgU7lNaB0UPzy!=X9*pDx)VYpEm2o8XDcp-*ZG&79@S50^I%R zAP5ubQ{-)-sW^nd0B;l1oJ27OFm@RJ4En!6AOe5{6+=M^1`;p@gFu9e!Ke%-y$Jgc z3kW9O>}07P+|XG&;)!ybfSxC|YHAWZrUPmlmX9F~;@VHA?(Nv|Sg^#Bn6 ztVfRX1OZec1W^Sc7?sThfKZT<0fb?)SphJBGsh1?j?Dx^pzM+W7{;g=j!-ZJz$j)A z7@Kg(*c}K8Qh69kQb7Wx#Dzk*Y-0cvN2ol4(l!8tCQdwN21Ag~$&mk70%M{S*Em2> zV#OgywyFRQf3DlOb>iRX0*=8G2N}yBCvZw>m=HjTnu$>R!NgG65&}$ux_1I#Qqm$| z2q4FoVJsQ~hp0p*HqrGMk3eNH5CADDfYLq5rV0WC@Wu4{udf0KA{0RoB4ksL(!T8O Y>*_!R1~K09Rpv7=oUWzCvN5Co12G;ijQ{`u delta 2358 zcmZuxdpJ~i7-p4+Y28vpr5QCI+Hh`jE^MWYNVz1p&_!-dxszpvPPIghZaXwROL9qA z($GBy8=BHZNF|lFT#7VBB3kWe+ctAL=bzv6KJWRy_j|wh{Dizwu1HyNHr?DIz@Ov0 zJS>*(O$THzjv{mxhSJy51g47qWc|_h(C4V;9_fb}mC-x*b-%eO=JQl8+tGskvaR?V zP8@jVzpdvfUSV~-YN?4$?)mfgmSx=CsR0`$*B*rDxU@)noiP4rk3jF!`%DKO=k2u= zvW|D1`6*>M$noP8DN}Ih-Xi>0soVJZCw~cpt554yY;N&G64-q06;OCV5*hQNORQU( z?taQYUz=gITFsK-9rrXLsK-!$c3zTO{Mx~dBc{ULGuG*54(RNT=)Yn8rg=~HS+~Ps zPv8A%s#-gwo_7g2R=c15FlAPVXbEvFL&LRgNaJI5L{`WV^P?x#tD+v)Ig3IU%uNS6 z4J$pnt}4}kdU0{SiR(P0eV19Dg-+87JU2UQq68jj|VZ!U#cqZdJ!U zVZ8eK(z5u-;T|o?2Lt9IhhDPXHnuiPyz)VSZ6LW{-zP-jLdm*5bLp}X@@&=2t1(0A zZ3Th##;5O>`zV+Wx-oU3;`#e{*B$zw>bNuwkJS)b>B40N9(y&gJmbq`G{1?~uuMO|qp~$7WFnY(z?e!d-k5-VO4d z2AU){PG==FcNrt&UUSN>Y;XzR6jQd|XK*m1x>xecqxf2DP87Fft->JUHjN1hXrZe{OxTPv4TI|TJ>eMn|T&V&ZjG#yt8iQ@--`5 zQ;(d@F*#sUQDUj#jjPurK#h>BVg= z7N*fd{gJ%Ih0IrBdmdjuO$!M1kBW{A@C}(bg>BwS10mUMr1JR$LeLq8vNJRl1wa-i zh{0`12%`fN4?UDl`+NXlf{@)`lQ9HOcg-F@f!3TU8jRF_|__ HD`@`!RTwZ> diff --git a/benchmarking/benchmark_incr_dec.sh b/benchmarking/benchmark_incr_dec.sh index 3ddcb2271a..3a75fa61db 100755 --- a/benchmarking/benchmark_incr_dec.sh +++ b/benchmarking/benchmark_incr_dec.sh @@ -42,7 +42,7 @@ request_per_second_values=( ) dataset_name="sharegpt" -dataset_fp="../wildchat/${dataset_name}.json" +dataset_fp="../benchmarking/${dataset_name}.json" partition_name="all" export LEGION_BACKTRACE=1 @@ -68,7 +68,7 @@ for j in "${!batch_sizes[@]}"; do metrics_fp="/usr/FlexFlow/inference/output/incr_dec_llm_${model_name_}_bz_${batch_size}_rate_${rate}_dataset_${dataset_name}.csv" rm $metrics_fp $output_fp $log_fp || true - time ./inference/suffix_decoding/incr_dec \ + time ./inference/simplified_infer/incr_dec \ -ll:gpu $NGPUS -ll:cpu $NCPUS -ll:util $NCPUS \ -tensor-parallelism-degree $NGPUS \ -ll:fsize $FSIZE -ll:zsize $ZSIZE -ll:csize $CSIZE \ diff --git a/benchmarking/benchmark_specinfer.sh b/benchmarking/benchmark_specinfer.sh index 5fe881f08d..e0c8e39d79 100755 --- a/benchmarking/benchmark_specinfer.sh +++ b/benchmarking/benchmark_specinfer.sh @@ -52,7 +52,7 @@ request_per_second_values=( ) dataset_name="sharegpt" -dataset_fp="../wildchat/${dataset_name}.json" +dataset_fp="../benchmarking/${dataset_name}.json" partition_name="all" export LEGION_BACKTRACE=1 diff --git a/benchmarking/plot_results.ipynb b/benchmarking/plot_results.ipynb index 39047b86ce..c7dcff18c5 100644 --- a/benchmarking/plot_results.ipynb +++ b/benchmarking/plot_results.ipynb @@ -164,7 +164,7 @@ "plt.grid(True) # Turn the grid on\n", "\n", "# Save the plot as a PDF\n", - "plt.savefig('/usr/FlexFlow/wildchat/average_accepted_tokens.pdf')\n", + "plt.savefig('/usr/FlexFlow/benchmarking/average_accepted_tokens.pdf', bbox_inches='tight')\n", "\n", "plt.show()\n" ] @@ -244,179 +244,179 @@ "plt.tight_layout(rect=[0, 0, 1, 0.96])\n", "\n", "# Save the plot as a PDF\n", - "plt.savefig('/usr/FlexFlow/wildchat/throughput_vs_tpot.pdf')\n", + "plt.savefig('/usr/FlexFlow/benchmarking/throughput_vs_tpot.pdf')\n", "\n", "plt.show()" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n", - "/tmp/ipykernel_3339078/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", + "/tmp/ipykernel_3415116/2453520981.py:48: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n", " ttft = group.apply(lambda x: x[x[\"request_step_idx\"] == 0][\"timestamp\"].values[0] - x[x[\"request_step_idx\"] == -1][\"timestamp\"].values[0])\n", - "/tmp/ipykernel_3339078/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "/tmp/ipykernel_3415116/2453520981.py:50: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " return ttft.mean()[1] / 1000\n" ] }, @@ -434,7 +434,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABVwAAALvCAYAAACZeQ7oAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADqJ0lEQVR4nOzdeVyN6f8/8NeptC9atJFKoiSh7EP2KCR7tsq+CxmMqGQdu5mxLxlK9u0jS4OIjGXsNJgohpQ1khZ1//7o1/11nJZTIqbX8/s4j++c676W93Wfuz68Xee6JIIgCCAiIiIiIiIiIiKiz6ZQ1gEQERERERERERER/Vcw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKCROuRERERERERERERKWECVciIiIiIiIiIiKiUsKEKxEREREREREREVEpYcKViIiIiIiIiIiIqJQw4UpERCJvb29YWFh80TEkEgkCAwO/6BhlYeHChahWrRoUFRVRt27dsg5HRsuWLdGyZUupsqSkJPTo0QP6+vqQSCRYtmwZAODevXto3749dHR0IJFIsG/fvq8e739NfvdfXhYWFvD29i7VeL60z5lvWbOwsECnTp2++DiBgYGQSCRffBwiIiIi+vqYcCWib45EIinVV1RUFOLj4wu83rhxY/EvvkW9vpUEwo8//giJRILevXuXdShfxKefl4KCAvT09NCxY0ecO3euxP2uXLkSISEhpRfo/3fs2DH8+OOPaNasGTZt2oS5c+eW+hgf8/b2lro/mpqaqFatGnr06IHdu3cjJydHrn4mTJiAo0ePYtq0adiyZQs6dOgAAPDy8sKNGzcwZ84cbNmyBU5OTl9yOp9l7ty5cieEP36uZs+enW+dfv36ifeUvjwLCwupZ1lVVRXW1taYPHkyXr58WaI+Y2JiEBgYiNevX5dusHJKTU1FQEAAateuDQ0NDejr66Nu3boYP348njx5UiYxEREREdHXpVTWARARfWrLli1S73///XdERkbKlGdnZ0NRUbHIera2tnj//j0AwNPTE66urlLXK1WqBBMTE1SvXl0sS01NxciRI+Hh4YFu3bqJ5UZGRp83uVIgCAK2bdsGCwsLHDx4EG/fvoWWllap9L1u3Tq5k3VfQ97nlZ2djbt372LlypVo1aoV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V3DlyhUAuXumypNwffPmDQ4dOgQ3Nzepw7w+NWrUKFSoUAGLFy/GgQMHYGZmhqVLl+a7J21GRobUCmFtbW00aNAAW7ZsQZs2bYqM6XP0798fa9euxcqVK/H69WsYGxujd+/eCAwMhIJC7nb6xsbGWL16NebNm4fBgwcjOzsbJ0+eLDLZOXPmTDx79gy7du0SD+Y6fPiwTLvKlSvj/PnzmDFjBkJDQ/HmzRtUrlwZHTt2FP9BoaQxEBERERGRNIkgCEJZB0FERERERERERET0X6BQ1gEQERERERERERER/Vcw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKiVJZB/AtyMnJwZMnT6ClpQWJRFLW4RAREREREdF/nCAIePv2LUxNTaGgwLVQRET/JUy4Anjy5AnMzMzKOgwiIiIiIiIqZx49eoQqVaqUdRhERFSKmHAFoKWlBSD3f+i0tbXLOJryISsrC8eOHUP79u1RoUKFsg6H6Ivgc07lAZ9zKg/4nFN5wOf863vz5g3MzMzEv48SEdF/BxOugLiNgLa2NhOuX0lWVhbU1dWhra3NP9DRfxafcyoP+JxTecDnnMoDPudlh9vaERH993CjGCIiIiIiIiIiIqJSwoQrERERERERERERUSlhwpWIiIiIiIiIiIiolHAPVyIiIiIiIiIqVdnZ2cjKyirrMIiISo2ysjIUFORbu8qEKxERERERERGVCkEQ8PTpU7x+/bqsQyEiKlUKCgqwtLSEsrJykXWZcCUiIiIiIiKiUpGXbDU0NIS6ujokEklZh0RE9NlycnLw5MkTJCYmomrVqkX+bmPClYiIiIiIiIg+W3Z2tphs1dfXL+twiIhKVaVKlfDkyRN8+PABFSpUKLQuD80iIiIiIiIios+Wt2erurp6GUdCRFT68rYSyM7OLrIuE65EREREREREVGq4jQAR/RcV53cbE65EREREREREREREpYQJVyIiIiIiIiIiIqJSwoQrEREREREREVE5FBUVBYlEgtevX8vdxsLCAsuWLftiMRWkJLF+Td7e3ujatWup99uyZUv4+vqWer/0ZTHhSkRERERERET0jfH29oZEIsGIESNkro0ePRoSiQTe3t5fP7BvmIWFBSQSCSQSCRQVFWFqaorBgwfj1atXxernayU5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L8X3kf5vG4r169erTJkycnZ21ksvvaSoqCijzaZNm/Tss88qT548cnd3V1BQkE6fPq3Q0FCNGTNGBw8eNFbahoaGSpIsFotmz56tV155RXny5NGECROS3fLiu+++k8VisTr2ww8/qHr16sqVK5fy58+vFi1aSLr77+D06dMaMGCAcb+U2rFjh4KCgtS+fXv5+/urYcOGateu3QPfaXBwsMLDw234BpNH4AoAAAAAALK1rVu3qmrVqsmeGz16tGbNmqUdO3bozJkzeu211zRjxgyFhYVp9erV+vHHH61WHk6aNEmLFi3SnDlz9Mcff2jAgAHq2LGjNm/erMKFC+ubb76RJB09elRRUVFGiHjz5k0NHDhQe/bsUUREhOzs7NSiRQslJiamelw3btxQkyZNFBERof379+ull15ScHCwIiMjrdpNnz5dQUFB2r9/v5o2bapOnTqpc+fO6tixo/bt26fixYurc+fOxiPtt2/fVtWqVbV69WodOnRIPXr0UKdOnR4Ir9IiMTFRhQoV0vLly3X48GGNHDlS7733npYtW2bV7ueff9bZs2e1ZcsWTZs2TaNGjdLLL7+svHnzateuXXrrrbfUs2dP/f3338Y1Li4uCg0N1eHDhzVz5kzNmzdP06dPT3FtSUlJioiI0NGjR/X888+bNuZ7atWqpYiICP3555+SpIMHD2rbtm1q3LjxQ6+5fPmyli1bpho1ath8v5iYGE2ZMkWLFy/Wli1bFBkZqZCQEElSfHy8mjdvrjp16ui3337Tzp071aNHD1ksFrVp00bvvvuuypUrp6ioKEVFRalNmzZGv6NHj1aLFi30+++/6/XXX09RLatXr1aLFi3UpEkT7d+/XxEREXr22Wcl3d3WoVChQho7dqxxv5SqVauW9u7da8zREydOaM2aNWrSpIlVu2effVa//vqrYmNjU9x3cnKk6WoAAAAAAIBM7vTp0/L19U323Pjx4xUUFCRJ6t69u4YNG6bjx4+rWLFikqTWrVtr48aNGjJkiGJjYzVx4kT99NNPCgwMlCQVK1ZM27Zt02effaY6derIw8NDkuTl5WW12q9Vq1ZW9/3iiy/k6empw4cPq3z58qkaV8WKFa0eZR83bpxWrFihlStXqk+fPsbxJk2aqGfPnpKkkSNHavbs2apevbpeffVVSXdXhAYGBur8+fPy8fFRwYIFjUBO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Hcb2Ge+//7527dqlokWLPrK+PHnyWH22s7MztqW45/69c52cnB7ZX2rt3btXFy5cUJUqVYxjCQkJ2rJli2bNmmWsWJaky5cvGytp04LAFQAAAAAAZGuVK1fWl19+meZ+ypYtK0dHR0VGRqpOnTrJtsmZM6ckGasQpbsvoTp69KjmzZun5557TpIeeBlTakLL7du3q2vXrmrRooWku4HwqVOnbO4nuX6bNWumjh07SrobxP75558qW7aspLsrQe9fMZnae9SqVUu9evUyjqX1JWKStGPHDvn5+en99983jt3/CHmOHDmMEPNxEhMTFRsb+8g2X331lV5//XWFh4eradOmVufM+J7udy80vBfMp3Qcj2OxWBQUFKSgoCCNHDlSfn5+WrFihQYOHKicOXNazeVH8fT01Llz55SUlGSE+PeHwi4uLvL391dERITxcrl/c3BwSPH97qlfv75+//13q2PdunVT6dKlNWTIEON7k6RDhw6pcuXKNvWfHAJXAAAAAACQrTVq1EjDhg3TlStXkn17eUq5uLgoJCREAwYMUGJiomrXrq1r165p+/btcnV1VZcuXeTn5yeLxaJVq1apSZMmcnJyUt68eZUvXz7NnTtXBQoUUGRkpIYOHZrmcZUsWVLffvutgoODZbFYNGLEiDS9hOv+fr/++mvt2LFDefPm1bRp03T+/HkjcH2UixcvWoVs0t1H2JO7x6JFi7R+/XoVLVpUixcv1u7dux+7qjIltUdGRio8PFzVq1fX6tWrtWLFisdeN2nSJFWrVk3FixdXbGys1qxZo8WLF2v27NlGm2HDhumff/7RokWLJN3dRqBLly6aOXOmatSooXPnzkm6u5LTzc3tofe6fPmyIiMjdfbsWUl3X7AmST4+PlZ7l16/ft0IMM+cOaPBgwfL09PT6sVVabVr1y5FRESoYcOG8vLy0q5du3Tx4kWVKVNG0t3tCNavX6+jR48qX758jxxX3bp1dfHiRX3wwQdq3bq11q1bp7Vr11qtvh09erTeeusteXl5qXHjxrp+/bq2b9+ud955x7hfRESEgoKC5OjomKJfry4uLg/sg5wnTx7ly5fvgeNbt27VuHHjUvz9PAyBKwAAAAAASFdrK1TN6BIeKSAgQFWqVNGyZcuMl0el1rhx4+Tp6alJkybpxIkTcnd3V5UqVYyXOBUsWFBjxozR0KFD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WjXZc6NHj9asWbO0Y8cOnTlzRq+99ppmzJihsLAwrV69Wj/++KPVKrlJkyZp0aJFmjNnjv744w8NGDBAHTt21ObNm1W4cGFjj8ijR48qKirKCBFv3rypgQMHas+ePYqIiJCdnZ1atGihxMTEVI/rxo0batKkiSIiIrR//3699NJLCg4OVmRkpFW76dOnKygoSPv371fTpk3VqVMnde7cWR07dtS+fftUvHhxde7cWUlJSZKk27dvq2rVqlq9erUOHTqkHj16qFOnTlbhVVolJiaqUKFCWr58uQ4fPqyRI0fqvffe07Jly6za/fzzzzp79qy2bNmiadOmadSoUXr55ZeVN29e7dq1S2+99ZZ69uypv//+27jGxcVFoaGhOnz4sGbOnKl58+Zp+vTpKa4tKSlJEREROnr0qJ5//nmbxnT9+nV5eHik+JqU+ueff/TDDz+oRo0aNl97/Phxfffdd1q1apVWrVqlzZs3a/LkyZKkqKgotWvXTq+//rqOHDmiTZs2qWXLlkpKSlJISIhee+01vfTSS4qKilJUVJRq1apl9Dt06FD169dPR44ceew2CvfMnj1bvXv3Vo8ePfT7779r5cqVKlGihCRp9+7dkqQFCxYoKirK+JwStWrVUkREhP78809J0sGDB7Vt2zY1btzYqt2zzz6rrVu3prjfh2EPVwAAkGXYsj9cavd3AwAAWc/p06fl6+ub7Lnx48crKChIktS9e3cNGzZMx48fV7FixSRJrVu31saNGzVkyBDFxsZq4sSJ+umnnxQYGChJKlasmLZt26bPPvtMderUMcI2Ly8vqz1cW7VqZXXfL774Qp6enjp8+LDKly+fqnFVrFhRFStWND6PGzdOK1as0MqVK41Vg5LUpEkT9ezZU5I0cuRIzZ49W9WrV9err74q6e6K0MDAQJ0/f95YURkSEmJc/84772j9+vVatmyZnn322VTV+m8ODg4aM2aM8blo0aLauXOnli1bptdee8047uHhoY8++kh2dnYqVaqUPvjgA8XExOi9996TJA0bNkyTJ0/Wtm3b1LZtW0l39+q8x9/fXyEhIQoPD9fgwYMfWdO1a9dUsGBBxcbGyt7eXp9++qlefPHFFI9pypQpunHjhlX9aTFkyBANHz5cCQkJun37tmrUqKFp06bZ3E9iYqJCQ0Pl4uIi6e4K24iICE2YMEFRUVGK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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAABVwAAALvCAYAAACZeQ7oAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADxCklEQVR4nOzdeVyN6f8/8NeptC9atJFKoiSh7EP2KCR7tsq+CxmMqGQdu5mxLxlK9u0jS4OIjGXsNJgohpQ1khZ1//7o1/11nJZTIqbX8/s4j++c676W93Wfuz68Xee6JIIgCCAiIiIiIiIiIiKiz6ZQ1gEQERERERERERER/Vcw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKCROuRERERERERERERKWECVciIiIiIiIiIiKiUsKEKxEREREREREREVEpYcKViIiIiIiIiIiIqJQw4UpERCJvb29YWFh80TEkEgkCAwO/6BhlYeHChahWrRoUFRVRt27dsg5HRsuWLdGyZUupsqSkJPTo0QP6+vqQSCRYtmwZAODevXto3749dHR0IJFIsG/fvq8e739NfvdfXhYWFvD29i7VeL60z5lvWbOwsECnTp2++DiBgYGQSCRffBwiIiIi+vqYcCWib45EIinVV1RUFOLj4wu83rhxY/EvvkW9vpUEwo8//giJRILevXuXdShfxKefl4KCAvT09NCxY0ecO3euxP2uXLkSISEhpRfo/3fs2DH8+OOPaNasGTZt2oS5c+eW+hgf8/b2lro/mpqaqFatGnr06IHdu3cjJydHrn4mTJiAo0ePYtq0adiyZQs6dOgAAPDy8sKNGzcwZ84cbNmyBU5OTl9yOp9l7ty5cieEP36uZs+enW+dfv36ifeUvjwLCwupZ1lVVRXW1taYPHkyXr58WaI+Y2JiEBgYiNevX5dusHJKTU1FQEAAateuDQ0NDejr66Nu3boYP348njx5UiYxEREREdHXpVTWARARfWrLli1S73///XdERkbKlGdnZ0NRUbHIera2tnj//j0AwNPTE66urlLXK1WqBBMTE1SvXl0sS01NxciRI+Hh4YFu3bqJ5UZGRp83uVIgCAK2bdsGCwsLHDx4EG/fvoWWllap9L1u3Tq5k3VfQ97nlZ2djbt372LlypVo1aoV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V3DlyhUAuXumypNwffPmDQ4dOgQ3Nzepw7w+NWrUKFSoUAGLFy/GgQMHYGZmhqVLl+a7J21GRobUCmFtbW00aNAAW7ZsQZs2bYqM6XP0798fa9euxcqVK/H69WsYGxujd+/eCAwMhIJC7nb6xsbGWL16NebNm4fBgwcjOzsbJ0+eLDLZOXPmTDx79gy7du0SD+Y6fPiwTLvKlSvj/PnzmDFjBkJDQ/HmzRtUrlwZHTt2FP9BoaQxEBERERGRNIkgCEJZB0FERERERERERET0X6BQ1gEQERERERERERER/Vcw4UpERERERERERERUSphwJSIiIiIiIiIiIiolTLgSERERERERERERlRImXImIiIiIiIiIiIhKiVJZB/AtyMnJwZMnT6ClpQWJRFLW4RAREREREdF/nCAIePv2LUxNTaGgwLVQRET/JUy4Anjy5AnMzMzKOgwiIiIiIiIqZx49eoQqVaqUdRhERFSKmHAFoKWlBSD3f+i0tbXLOJryISsrC8eOHUP79u1RoUKFsg6H6Ivgc07lAZ9zKg/4nFN5wOf863vz5g3MzMzEv48SEdF/BxOugLiNgLa2NhOuX0lWVhbU1dWhra3NP9DRfxafcyoP+JxTecDnnMoDPudlh9vaERH993CjGCIiIiIiIiIiIqJSwoQrERERERERERERUSlhwpWIiIiIiIiIiIiolHAPVyIiIiIiIiIqVdnZ2cjKyirrMIiISo2ysjIUFORbu8qEKxERERERERGVCkEQ8PTpU7x+/bqsQyEiKlUKCgqwtLSEsrJykXWZcCUiIiIiIiKiUpGXbDU0NIS6ujokEklZh0RE9NlycnLw5MkTJCYmomrVqkX+bmPClYiIiIiIiIg+W3Z2tphs1dfXL+twiIhKVaVKlfDkyRN8+PABFSpUKLQuD80iIiIiIiIios+Wt2erurp6GUdCRFT68rYSyM7OLrIuE65EREREREREVGq4jQAR/RcV53cbE65EREREREREREREpYQJVyIiIiIiIiIiIqJSwoQrEREREREREVE5FBUVBYlEgtevX8vdxsLCAsuWLftiMRWkJLF+Td7e3ujatWup99uyZUv4+vqWer/0ZTHhSkRERERERET0jfH29oZEIsGIESNkro0ePRoSiQTe3t5fP7BvmIWFBSQSCSQSCRQVFWFqaorBgwfj1atXxernayU5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wYIF1ahRI928eVOhoaFatGiR/v3vf8tkMslkMmnz5s2W5SGWL1+uevXqKV++fFq2bJnlXA/fo4dnlX/11VeqUqWK7O3tVbRoUQ0cOFCSLO3atGkjk8mU7tnosbGx6tKli+bPn5/iLOACBQooICBAERER6eo3JQSuAAAAAAAgV9u2bZtq1kx5KYLQ0FDNnj1bO3fu1Llz5/TGG29o5syZCg8P15o1a/TTTz/ps88+s7SfPHmyFi9erC+++EK///67hg4dqq5du2rLli0qUaKEvvvuO0nS8ePHFR0dbQkRb968qaCgIO3du1eRkZGysbFRmzZtlJSU9MTXFRsbqxYtWigyMlIHDhxQs2bNFBgYqKioKKt2M2bMUEBAgA4cOKCWLVuqW7du6t69u7p27ar9+/erTJky6t69u8xmsyTp9u3bqlmzptasWaMjR46ob9++6tatm3799dcnrvVhSUlJKl68uL755hsdPXpUo0eP1gcffKAVK1ZYtfvll190/vx5bd26VdOnT9eYMWP06quvqkCBAtq9e7fefvtt9evXT3/99ZflGGdnZ4WFheno0aOaNWuW5s+frxkzZqS5NrPZrMjISB0/flwvv/xyuq7pxo0bcnd3T/MxafX333/rxx9/VJ06ddJ97MmTJ/XDDz9o9erVWr16tbZs2aIpU6ZIkqKjo9WpUye9+eabOnbsmDZv3qy2bdvKbDYrODhYb7zxhpo1a6bo6GhFR0erbt26ln5HjBihwYMH69ixY49dRuG+uXPnasCAAerbt68OHz6sVatWqWzZspLuzU6VpIULFyo6OtryOa0GDBigli1bphpkP//889q2bVu6+k0Ja7gCAAAAAIBc7ezZs/Ly8kpx34QJExQQECBJ6t27t0JCQnTy5EmVLl1aktS+fXtt2rRJw4cPV3x8vCZNmqSff/5Z/v7+kqTSpUtr+/bt+te//qV69epZwjYPDw+rNVzbtWtndd6vvvpKhQsX1tGjR1W1atUnuq7q1aurevXqls/jx4/XypUrtWrVKsusQUlq0aKF+vXrJ0kaPXq05s6dq9q1a+v111+XdG9GqL+/vy5evGiZURkcHGw5/t1339WGDRu0YsUKPf/8809U68Ps7Ow0duxYy+dSpUpp165dWrFihd544w3Ldnd3d3366aeysbFRhQoV9PHHHysuLk4ffPCBJCkkJERT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aezYsRoxYoR69eql7t27KywsTBERERo0aJCqVq2qChUq6NNPP33so+qPM336dL355puqW7euChUqpOHDhysmJiZDfUr3Xjp16tQpNW3aVI6Ojurbt69at26t69evP/bY8PBwhYeHW20bP368Zbbsff369dOBAwfUoUMHmUwmderUSf3799e6desyVPtrr72moUOHauDAgYqPj1fLli01atQohYaGpnrczZs31b9/f/31119ycHBQxYoVtXTpUnXo0MHSJjo62mqN2Xnz5unu3bsaMGCABgwYYNneo0cPhYWFPfJcq1atUq9evSyf77/sa8yYMVZ1jh49WqNHj5Z0b/Zo7dq19dNPP6lgwYJpuRVp4uLioq1bt2rmzJmKiYmRt7e3pk2bpubNm0uS+vTpo82bN6tWrVqKjY3Vpk2bLOsPP6xSpUqaM2eOJk2apPHjx6tdu3YKDg7WvHnzLG169Oih27dva8aMGQoODlahQoXUvn17y/5p06YpKChI8+fPV7FixXTmzBmdOXNGpUqV0qZNmzL0Z2bXrl26fv261fmelMn88OIJuVBMTIxcXV11/fr1VNe0gHESEhK0du1aVb5WWbayfWz70nX/TN8JyjV5wsoA4zDOkRswzpEbMM6RGzDOn76c+HPo7du3dfr0aZUqVeqxL6Z5Fq1Zs0bDhg3TkSNHrF7CBODZtmnTJrVt21anTp3K0Az1Dh06qHr16pZ/HHlYev6OY4YrAAAAAADI9Vq2bKkTJ07o77//VokSJbK6HABptHbtWn3wwQcZClvv3LkjX19fDR061JCaCFwBAAAAAAAkDRkyJKtLAJBOn3zySYb7yJs3r0aOHGlANfcwRx4AAAAAAAAADELgCgAAAAAAAAAGIXAFAAAAAAAAAIMQuAIAAAAAAACAQQhcAQAAAAAAAMAgBK4AAAAAAAAAYBACVwAAAAAAAAAwCIErAAAAAADI9f755x95eHjozJkzWV1Kmm3evFkmk0nXrl2TJIWFhcnNzS1La3pSZ86ckclk0sGDB7O6FORSL7zwgr777jtD+spjSC8AAAAAAACPkDD2vad2Lrsx057ouIkTJ6pVq1by8fExtqCHbN68WQ0aNNDVq1ezbTj6pOrXr68aNWpo5syZWV1Kun3//feaNGmS/vzzTyUkJKhcuXJ677331K1bt1SPmTt3rg4ePKj4+HhVqVJFoaGhatq06WPP9cUXX2jfvn26cuWKDhw4oBo1ali18fHx0dmzZyVJNjY28vT0VPPmzTV16lQVKFDgkX2HhYVpyJAhlpA+o3r27Klr167phx9+MKS/xzGZTFq5cqVat26druMSExMVGhqqpUuX6sKFC/Ly8lLPnj01cuRImUwmSdLIkSM1dOhQtWnTRjY2GZujygxXAAAAAACQq8XFxWnBggXq3bt3VpeCZ5S7u7s+/PBD7dq1S7/99pt69eqlXr16acOGDY88ZuvWrWrcuLHWrl2rffv2qUGDBgoMDNSBAwdSPdfNmzf14osv6qOPPkq13bhx4xQdHa2oqCgtW7ZMW7du1aBBg57o+jJbQkJClp7/o48+0ty5czV79mwdO3ZMH330kT7++GN99tlnljbNmzfXjRs3tG7dugyfj8AVAAAAAADkamvXrpW9vb1eeOEFy7b7j+tv2LBBfn5+cnBw0CuvvKJLly5p3bp1qlSpklxcXNS5c2fFxcVZjktKStLkyZNVqlQpOTg4qHr16vr2228l3XtsvkGDBpKkAgUKyGQyqWfPnpKk9evX68UXX5Sbm5sKFiyoV199VSdPnszQdZ08eVKtWrWSp6ennJycVLt2bf38889WbXx8fDRhwgR1795dTk5O8vb21qpVq3T58mW1atVKTk5Oqlatmvbu3Ws55p9//lGnTp1UrFgxOTo6ytfXV19//XWGan1YYmKievfubbmPFSpU0KxZs6za9OzZU61bt9akSZPk6ekpNzc3jRs3Tnfv3tWwYcPk7u6u4sWLa+HChVbHDR8+XOXLl5ejo6NKly6tUaNGPTYQrF+/vtq0aaNKlSqpTJkyGjx4sKpVq6bt27c/8piZM2fq/fffV+3atVWuXDlNmjRJ5cqV048//pjqubp166bRo0erUaNGqbZzdnZWkSJFVKxYMTVo0EA9evTQ/v37Uz3mYaGhoapRo4aWLFkiHx8fubq6qmPHjrpx44alzbfffitfX185ODioYMGCatSokW7evKnQ0FAtWrRI//73v2UymWQymbR582bL8hDLly9XvXr1lC9fPi1btsxyrofv0cOzyr/66itVqVJF9vb2Klq0qAYOHChJlnZt2rSRyWRK12z0nTt3qlWrVmrZsqV8fHzUvn17NWnSRL/++qulja2trVq0aKGIiIh03cOUELgCAAAAAIBc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", "text/plain": [ "
" ] @@ -489,13 +489,13 @@ "pivot_df.plot(kind='bar', ax=ax, color=colors)\n", "\n", "ax.set_title('TTFT vs Arrival Rate for Different Models and Batch Sizes\\nLLM: LLAMA-3.1-70B-Instruct')\n", - "ax.set_xlabel('Arrival Rate')\n", + "ax.set_xlabel('Arrival Rate (requests/sec)')\n", "ax.set_ylabel('TTFT (ms)')\n", "ax.grid(True)\n", "ax.legend(title='Model and Batch Size', bbox_to_anchor=(1.05, 1), loc='upper left')\n", "\n", "# Save the plot as a PDF\n", - "plt.savefig('/usr/FlexFlow/wildchat/ttft_vs_arrival_rate.pdf')\n", + "plt.savefig('/usr/FlexFlow/benchmarking/ttft_vs_arrival_rate.pdf', bbox_inches='tight')\n", "\n", "plt.show()\n" ] @@ -740,13 +740,13 @@ "pivot_df.plot(kind='bar', ax=ax, color=colors)\n", "\n", "ax.set_title('Queueing Time vs Arrival Rate for Different Models and Batch Sizes\\nLLM: LLAMA-3.1-70B-Instruct')\n", - "ax.set_xlabel('Arrival Rate')\n", + "ax.set_xlabel('Arrival Rate (requests/sec)')\n", "ax.set_ylabel('Queueing Time (sec)')\n", "ax.grid(True)\n", "ax.legend(title='Model and Batch Size', bbox_to_anchor=(1.05, 1), loc='upper left')\n", "\n", "# Save the plot as a PDF\n", - "plt.savefig('/usr/FlexFlow/wildchat/queueing_time_vs_arrival_rate.pdf')\n", + "plt.savefig('/usr/FlexFlow/benchmarking/queueing_time_vs_arrival_rate.pdf', bbox_inches='tight')\n", "\n", "plt.show()" ] diff --git a/benchmarking/queueing_time_vs_arrival_rate.pdf b/benchmarking/queueing_time_vs_arrival_rate.pdf index e77da10bad2cce12d587cb6ea92c4d3eada9af5d..a552ebceae828b0ead4e669f2c27f21348b35997 100644 GIT binary patch delta 4353 zcmZuxc_37K8;)iyV;Ot4IGU1>nKS2{S+Y~s5SmOXne4KKvUD{W*($`8hT__HvgD?; zlC_p`^MgrRbZfd%wQS_xtC(zvsN?dEe*#J-;)5TqrqHsJ=@GbzuKP9J^b{ zmf7k7m957{+mEhF8Srjbr-uak8=F~#OQ_r<_irICHmjXEPYN3fsBOs{Zm;?h74=j+ zq~<_dG#>FlH7|HQKa)JPu)fvV{ssEc(Ic#r(Q-Dz=i#04uEdS2hc^}|+-jYPj3J93-*v+gK*R~v_&*Xt3tNNeX*7tT6pJz^RGouw^{gKqQmV@qftSvHe52ECzXW#kb zsVKP&=>|pqi*?fyqJ!2o*Vvxr8J$H}GY2g3qt-bS@%@3gmM z$s^B_{xno^;p8SFBS~7OGLy{N9+;c)7zhitehiqqqe8Cladsu5Za8W>;o`bPD4_0! z*WNbviFdJsEm>OM`;JI1 zI$hzah`gSNiFE|Evog|hokt6z3*Or%0n4z$^2~gE(b|D~p9X9cXw@s{ zBI({XtO<9z-mw#VCw+{9HYRVl$@;UW=69{iEfL$+1so%ZeWQfA3xs^z|#zgQM%omkw!)K~z&WKsC}GRKtj(t5bk<5efOdzELD$?60u z+1nL7^R|hd?TpzQR63?=7-z&+LwCWrSNVuZY(DE5DRxONE-lX_-)f#CC7BMmSNqtA z9Lw>bzojKrG<;T($g%0Y*m>+^>0gQ^&pXPl`qnaUJI`SfN}J4+fb0d&^O0*-$V_wc zGsce#Ur-gL(xS12%$*(U*HA0+%{pgWWkdRij`NI?ag>mW>H5K)J>(ndQ!zN_t?QMT zx&6CUg#G?1J3UvZljGSrds!Cu5(*)5tMn~L5z(`pxYF&c`(0$N{i*)vM3IKtORgJx zF8X_Ue-q^Q4F*f<8l&ictQ*@}zi9!*KauX@ zkIO|N?jhE7Ww@*qKUI+AsCl3MiGvBV#aUe}NDgZpRXXYLW@uhb9M;QaXNVA(hJI?K zR`2cw&)qp@@)BLYuRJ{7LV5>`4KZf6e)YS^IPEt5b$5kT&#vK;2(+8#W6fbb%B#ic zxTHg!iKIxD3m#y79QA7jh6IFiSZRT_-ClU(5&N zSpQ~fhuprKkovAui|P9)$@1USy{p|Wt+gt$6&-N^-;clWjf=Wg_4)JNqQXsZWj!9? z+%zxmU&z8tzTbIA17>bIz!rnQ%_=QJ?&^Yg(UKFvliwzwan z7&>BCM)titu^1p#=ojnlH)NRT)cm^j)1TCeJ9V<1B`79pFl!ZRJEgLoS|a0Wtk>sa zdF=R^nSK5pWDAeLvpRX5^O2_H7cI}}@#D%mTX$=fdp6y!bnppJDa}4>-a$XXSXbTb zcFP^1QB#V!^4MuQwyxhb@qS@4=jBvkw)SLZ!|2?gS|M!UtvyMdnaot;Vj8lyCEhP8 zC!Lzo%4U{Lf(9Yt_F)BO_o~OzHPCdifXco5Xanl8DV6yefdMRyHR=XThgdh?X$9lX zmByGyHZAZRciXH&kdkq8^b=)|A)u ztlNj}#pXR}ED<+TNCWujAZYh7-m9F#Va+)z~eq@yh3M2O`h&S$hw@L^2AJO671XKCG#j#@t0 zF~Bs5`_g!^b+^Gt%{lTTiRLYKmxsyS2Ud#ITzvd4j$yu`Za(g`h2;$l*3OO3PH^V2 z>wc8VU;e-%O~mPQxSza`XY0~0c-g0ZjZFIRyZJUqX_p6HS+C3KdROXBcmY}-5 z6da0)_PlqxGjX|$ijw~>Wd$@*YF4r?$*-%#&R}$+{pILf+1OT-Cy3*C@rBwQ()!s~ zHq=&Q4x;sDsjdu#vW|Rn&zP>=USaUSNW-_~KFQ5O?5h$hg+WTwumm1hPJ|(LkLoI> zgL7-`a!~S>aiS9C`uyXoF$U4m9X{VkC1+8U8!Z)V@3gyK^1jQ6v$L{EH^2s~+6P@S zB3rm7A7xeUO?`Q?I;X75Ro|ie{mAyZ7s{gtY2?1Avnd|Jna(U4BVPK1VTW8O0L&5=2&$LW`)I(xMwr95&)YQp-{I6#9Mt`zGb zs?u8@wMk?D1?6{FcicMJ`tU)VbKHwvuQkPPsIC2UQ0T7OE)R@Ph<8L}xDO+k7qOq{ ztFR^Y``IxD@=YJ~j|j0v@$&5B1_#*;-jlvsn@DmaEVI~Uk3)L_Lr-qIXmy;pce@YO z)iur%e-XA_Ie|7FreYSrDN?VKtb><*IU=peRwrn)Rq@vBE>NBwiEm}gK=Mr%grhue zSib2gNDyM@zzS>}G{#=aepvgo8hS{LGq7cHiHYfN|$-Hv>1%v>Y z?*T|6Lp=JW7@0@E1f%j)3t$jW+R{7(VUL(^5Jt#sRSRtCyW6mY2o0z`!b2w?*G2jTzl!9<8R`d*P&{5JEyoOo4Hc$byPV6uw7)cFm8- zAm4*aFqra-y6<^ZSRjuA^4-i|%>O!#K!F7nQ%JDDWT*tb;rZ+5w^Sl^sb>gOm?$uQ zDnj}-k3WAZPu>zjkU#)`P2>RtBL4>eQWzv4uz>9eB@(Z z3-Cb#*I1PR!UO>agJc3kV(VI|^G+Y{5*iu_{P>;WZ9{xR0ltxWe^e6_OhhCjJTf}m T#}@;VK?)hOX3ZuiE6jfYXV-uO delta 4014 zcmZWpc_38#7k@liW~3t78Cj|!b7$_IJ2S!~Srf8ETCJgMlMs)~NcJo@@+e!@ED_Qp ziHba>1|dm`h(vxyipp>1)qAhZ_pfu$J>PTA=kxuX6P?1dl)zK6LvS%isdJIPtZZzdk+Pu3POA18KjWfS^1g)(!Hpxxnmv5l%4wsj z;aFQbZeViM!zL;AwzNjLDnmY1nwV%Uaehp)ut_o8Z~ydDo-ro45d_Lu2rH?(^h#yYU4VMOGsh^{SCj9;__&4Q3yG1*56qs~fuZ7KqW zdK^;}g|d%3R;cf+%)2mGwLxxbJyz4GChTm%&WHO83$_m`4|IN{ZW1-c3fI?O=}hir z98lb8iVZd5ZAyqvq~;$6UYt!iEV@yl-p2mem3&3U!`|llPlT@b)Jw;e7!sK&KB-?9 zYo`sj?^jdq-Lxq!6>*yozE>TG#fay=No2o!F{fnwU(8HR#cs{=g!7~;R&I$Lc)2C} z)we~QMHMHR3KJF8Y3Ghlv*sW+8fTMj?xpF9>VO}Esrbf}MgGnmKxMdBq$^6Py9GP8 z*h%HLjUQ8Y*}P{$o?w+8XP2BRk+qarw;3^dt|pw`#V^IM{}9RSPCKYuyzpSs*hcq`K7<^$&uysH?CGTFJGT&e@5jKeA zio5h~J$ygKP)xbHcg;5cD{6ELhTOAd!?dk7Tl`#iMh)t_$3>>earXuXm{&CPMWY*-I_AESaY6wnW@TdYJui(zcNUFh z@g=9#T$sd`@ye1iJyv*+Qi3=CkX?oC$X5$d9WYuz_Ze37%<{O-fBOc*+^k z#F)MP_9yU~GA@D}kM4h0eFE>Wg)=5DiKgvN*5?8OLj_(cNtKk#4=U?ANP)PZS?XHB6xEt$XRxvVCjTaQ%Xu5TuqlkEZYw5QQ%IL_kOG za?34JgzBb@-*)`c>F4!IudV*hQ0d1<^g9|?2R=1hCgwLbm`q?Qb*}x^VCUQS<>{d> zZC_8{8*ai88~etjGIu{XQ)=Q=(Be40PSsF8I^$61vhYI{x7J=|A_jX*_L zqa@yPB%rpp?gsvZi1u9@i*pD77FGh;qUM>!TglNLaRaPjO|EmG+^+E9dJEPt zp+O5b9Kxt&v!W*A`j3ArlL(Y8HxkLh(`)8!bgpaF@_NnG^yeFYU0f&9?c7+A!%J0v z6k4h2szs!Xo9`QXhatD0 zneq1CH{iuunEF~8viy3~^UJ`Y7s#~6)tvO4hQ+{@1KO{YoObldktEN(E-*dr)vV%V z0ZBf{qWG)~H=RD&w;c#jzs7>k$Ja|FQn2?NU*3KFs(-n?INGPPIQZhlBPAs%FC`SH z2bW%i0MXWEmfQZ2mO-@Rk7bVLRljl28@;N_cL5$zwr<%l1l!KV#PS>IUXsz+uSf0% zgc;Ip#rfjHd1W(&kMWtSuaA8DsfoArFVJo)MURR6NdR6yO`f=@5r zw%ZN~fAsxOZ{EY&@2)v5IiFFKCy}M|`Q}>9Y-pBp3S+xQ?Ziu}T82mUG2eaO^TLCl zt$W;jj%mUAog>Ckh6gil|8 z*4rqDtt!JaGVYD$pPvj(f4o(Nle7DBYj~fTHG-r#9&`&)tfmkIcu*E`BRUCo zE{~V8wS9^AgZnpAP|jxiF0t?ILzM$5hii^TJ58niu0Lfg10gwu?pYo@|07xVK4dcgz5Wv+S0Fg*s6hLIQrhdqWaBPUmQ3&V! z`yK$91hX};%Ezw4$ig{WS6_m2>!~!IafSh-~-j zghYS@txiY;$RL*p0hoJi02;tGB19qxBCFnxNF;Ig0O$P6412>+xi3>`TyZ3}Tvy*E z5xM7;1cLv7L;hU=BnlU;L=d2Gp#wp#5hH>S*W?gEn8?K{TW~+*^QSv{>^$L0$7pHc z2-Y6KuI%-MBUt(P_~Y17oJDHl?Z#ek-*zc`m!0%?r2GH9$%q`4VpLQNEDSOK2Z`PN AdjJ3c diff --git a/benchmarking/throughput_vs_tpot.pdf b/benchmarking/throughput_vs_tpot.pdf index d17ec837758d25c127c21785e653e3386e33c13a..064bfb661cbdd158052970b88e25d7d7e6064c77 100644 GIT binary patch delta 7168 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 delta 3929 zcmZuxc_5VA8_qH%(DH3Cy`mq^e zelyQTKP@t+|M~;9*sjamQ+nQdXNUFpY!Y*R-BMUVCgvhA%p*Y8T8}HDQu&EIE($LP`F0#i|3mLlG^?(u2{o)s#;>gK18w<-MX5`nZldcxY#V7-6TS8Bg^jJ~MS=PK^;rt&HJ^{OQJk9lvI6LI8QmRL9T=fzhZ|f0{XhzB=r+6qr6^S*s>X)2OVC z-$qGm*?F=#jWX#OSBCi0p{dFheUPvw$Pp#nDd-HSYGH(19E zR#M5%qJHYL*UKnFsbqlx7ZcxsTa(UB1xXY9stMD3bdaG}eQ8O~Ni^ZzBbmMq8Zu%% z3b$-51pC6_)K`3T2VoNy|Nd^14syr2Acl)Yt27!9;}eIQR$q7B-%aQsi($|1lTR>x z9$r2-M90f{H%4`t5K>r~PC^n4zKYcePvxu&g35T5vVK1sA!t63IYr=qFSu3*$PSC? zeX!0?)GK>ilhgscu5*{ouCBN+3cvP~?qj=S3SU^lftT)R_J!xq70?gM<*tg~pv#Qp zH8$bzxhuc_2!Ph&t{086~r|&ZS8gIiJxd2M}Pr#BuF=jS7eMkz-r;@~IT% zQogX&u}=}+%|an3c(U`iSKa|$$^a*+dJ5V0OclC+xE1=zod;{J{k*ybd8Oh{2SX1< z;Fn?&-}bD&KF3?vCMX>d=~3-ozdK&gd@M7jXotXc_vpH|Ez+G4LS(1XnFYc7b1F)j zhu3u}Hy=Eb&V z^z?#7f1|1j!Sfr`d6WsGld$1CIyVO*0sTBK{14*d*^z(kgQV)v;&zTLw#>HXEC9ULH zbYzKRlpx(qS$~E%LB?;`ofOqr;!%815nEV&#KdX9!A3tOi8N+%)8?@(aSNS9eqHz? zy>D+JgF{Z-Nv@_YjMOeYO4%(P_(xjQjKzbO;E}#K(J6Y(maYEP3sXZk8;hMrwPT4C?UJk+Z zCZu1$pdu$MqN{So-mY?=Y{6|X*c;)PkbH*~#kv^fKq0!GHFWvNI@;DoTkzUG!k~tS zSoBS4e&IJVbYhyD_K)3wy$W#A4LL{vT_`AI_t^NiDXfAWWz$RSl;Qyqazmy&9qKIKf-M$fd3imU|W zl=x6G#?@clgw- z%ZKDk_Qdl(L0<#EPkUIwhDEkz{Jna=Crxgg(J`%VryN}qnKjZ$TvSvkyt2g8RFFot z`UmSTT_=RCzn`Nb<{9i8iiUzJ z)Ym4TVSqHOUl69-S zO*AMQp8dEp*f*fZPb5VZ3{+IQtUpb8Vt#MGwM_5k?k~69!(}2AD*SHs;0e@m&-Dr6}r?bViW8?<>>rGRVdEY)Y$9;7+^8115ZK z z4F($I8`qRJe)!JF+f%Lp!}EMS)v+70XLOB;#q^KH#qF{)cT4qWbG0bXNL}5 z(4G~3e7|Sj!>^JmQ1mV5z?quQt?P$99*>G)Xw-^h`c=%MEX+IP!q>)~yZzI_n;*~v`@jS>BJ78*oJV>*qI8p<=M-FMRnIMc@ z1SF6h*l;8Zl&I{+9^zexCt|dMX-ozh*#S}3V6;py+Bh^44^h@*w7fA|K4>il1_bey zZ=vkfFcX6(VE~LRM#~Qa0ly;JNtzD^0)NeXUEOII2>Wy9kAZNU2(9IRlu2Xb_+NMc z0|P-n;}aN&@H0AzfwX@{!5E16D`HE-KtGcjR0`?icz6KB$RJ9Z0AK;gSru(yfTsBz zX1IBx1DP}rG=L$1$U6f7#u3?PaR$Z*gZ>eK5XjNI5+ky;uE20uw$7Cpo~?H!Mqn#n zhOsAvA3P-4P=S|-MJf%IVFKHmWh@W}5xFwpaN1mou|zDFIy?clk_TW(>?XZD2Y~yf z1c3jw0Knn@50QXl`@2jafYau(55SSYmG%L60MCBl<$Lk$hxsoCbC&VY|Jh99@)>{t z0@qC-EXa*PByNlZa9xCe1>u!e0|XqWqL!;B;7QyV5#YL=Hi%tzJI*QE5Q&>d{M%{x zp9%!DNd$IXFHcNdVHanWh{LU{8Gwk_=1NS2NL-gAl2!=h_)h}4iVz^-Ip35s{uM|f z09?gIBH~uQI|u-rue@w82!PxL4B$Zk<{}col}SK=#PuW~2ynX1@+55cSGoX#1TI%W zkn~S|;Qna0UG@T2Bw7Wk(OD{pd3k3AvwL aklls+{9T#;KY9=dK_nttNy*sS1pPlXck4g^ diff --git a/src/ops/kernels/inc_multihead_self_attention_kernels.cu b/src/ops/kernels/inc_multihead_self_attention_kernels.cu index 28257edbd4..1f5ae1bb91 100644 --- a/src/ops/kernels/inc_multihead_self_attention_kernels.cu +++ b/src/ops/kernels/inc_multihead_self_attention_kernels.cu @@ -403,13 +403,13 @@ __global__ void apply_pos_encoding_to_streaming_proj_kernel( // Apply the rotary position encoding. cuFloatComplex cii = {kv_cache[real_part_idx], kv_cache[complex_part_idx]}; size_t pos = token_idx; - float freq = pos * (1.0 / pow(rope_theta, (float)2 * offset_in_head / head_dim)); + float freq = + pos * (1.0 / pow(rope_theta, (float)2 * offset_in_head / head_dim)); if (llama3_rope) { float pi = CUDART_PI_F; float wavelen = 2 * pi / freq; - float low_freq_wavelen = - original_max_position_embeddings / low_freq_factor; + float low_freq_wavelen = original_max_position_embeddings / low_freq_factor; float high_freq_wavelen = original_max_position_embeddings / high_freq_factor; if (wavelen < high_freq_wavelen) { @@ -439,7 +439,7 @@ void apply_pos_encoding_to_streaming_proj( // apply rotary embedding if needed if (!m->rotary_embedding_meta->apply_rotary_embedding) { return; - } + } int const kv_hidden_size = m->num_kv_heads * m->qk_dim; int num_tokens = 0; for (int req_idx = 0; req_idx < BatchConfig::max_requests_per_batch(); diff --git a/src/parallel_ops/kernels/allreduce_kernels.cu b/src/parallel_ops/kernels/allreduce_kernels.cu index 8644a5a3cf..cab5f749b9 100644 --- a/src/parallel_ops/kernels/allreduce_kernels.cu +++ b/src/parallel_ops/kernels/allreduce_kernels.cu @@ -149,7 +149,7 @@ void inference_kernel_wrapper(Legion::Context ctx, // if (strategy == tensorrt_llm::AllReduceStrategyType::RING || // !CanApplyCustomAllReduce(num_elements, dtype)) { - // Dispatch to nccl AllReduce if the customized all-reduce cannot apply. + // Dispatch to nccl AllReduce if the customized all-reduce cannot apply. ncclDataType_t nccl_data_type = ff_to_nccl_datatype(dtype); runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllReduce(input.ptr, diff --git a/src/runtime/request_manager.cc b/src/runtime/request_manager.cc index 734855fa59..4b68367543 100644 --- a/src/runtime/request_manager.cc +++ b/src/runtime/request_manager.cc @@ -488,7 +488,6 @@ size_t RequestManager::get_num_ssms() { return ssm_models.size(); } - RequestManager::RequestGuid RequestManager::register_new_request(GenerationRequest const &req) { // Add a new request @@ -739,7 +738,6 @@ bool isPrefixAndRemove(std::vector const &prefix, std::vector &vec) { return false; } - void RequestManager::request_complete_clean_up(int batch_index) { RequestGuid guid = guid_of_requests[batch_index]; profiling_requests[guid].finish_time = From 30efe4d60f97408f545e7c8432ba74f1b9cad129 Mon Sep 17 00:00:00 2001 From: fruitea Date: Fri, 15 Nov 2024 23:24:48 -0800 Subject: [PATCH 3/5] feat: use custom allreduce for performance --- include/flexflow/utils/communication_buffer.h | 5 +- src/parallel_ops/kernels/allreduce_kernels.cu | 128 ++++++++---------- src/utils/communication_buffer.cu | 22 +-- 3 files changed, 66 insertions(+), 89 deletions(-) diff --git a/include/flexflow/utils/communication_buffer.h b/include/flexflow/utils/communication_buffer.h index 5935c48598..3c14284d68 100644 --- a/include/flexflow/utils/communication_buffer.h +++ b/include/flexflow/utils/communication_buffer.h @@ -24,7 +24,6 @@ #include #endif #endif -#include "legion.h" // adapted from https://github.com/mlc-ai/relax @@ -59,9 +58,7 @@ class CommunicationBuffer { int *barrier_flag; }; -CommunicationBuffer *create_comm_buf_with_local_ptr(Legion::Context ctx, - Legion::Runtime *runtime, - int num_devices, +CommunicationBuffer *create_comm_buf_with_local_ptr(int num_devices, int device_id, ncclComm_t ncclComm, void *allgather_src, diff --git a/src/parallel_ops/kernels/allreduce_kernels.cu b/src/parallel_ops/kernels/allreduce_kernels.cu index cab5f749b9..2574cce2f4 100644 --- a/src/parallel_ops/kernels/allreduce_kernels.cu +++ b/src/parallel_ops/kernels/allreduce_kernels.cu @@ -58,9 +58,7 @@ AllReduceMeta::~AllReduceMeta() { namespace Kernels { namespace AllReduce { -CommunicationBuffer *get_or_create_comm_buffer(Legion::Context ctx, - Legion::Runtime *runtime, - AllReduceMeta *m, +CommunicationBuffer *get_or_create_comm_buffer(AllReduceMeta *m, int num_devices, int device_id, ncclComm_t ncclComm, @@ -71,9 +69,7 @@ CommunicationBuffer *get_or_create_comm_buffer(Legion::Context ctx, return iter->second; } else { CommunicationBuffer *comm_buffer = - create_comm_buf_with_local_ptr(ctx, - runtime, - num_devices, + create_comm_buf_with_local_ptr(num_devices, device_id, ncclComm, m->allgather_src, @@ -123,8 +119,8 @@ inline bool CanApplyTwoShotAllReduce(int64_t num_elements, } // Customized all-reduce kernel backed by CUDA Peer memory. -void inference_kernel_wrapper(Legion::Context ctx, - Legion::Runtime *runtime, +void inference_kernel_wrapper(Context ctx, + Runtime *runtime, AllReduceMeta *m, BatchConfig const *bc, GenericTensorAccessorR const &input, @@ -138,72 +134,68 @@ void inference_kernel_wrapper(Legion::Context ctx, assert(input.domain == output.domain); size_t hidden_dim_size = input.domain.hi()[0] - input.domain.lo()[0] + 1; size_t num_elements = bc->num_tokens * hidden_dim_size; - // int num_devices = m->handle.num_devices; - // int device_id = m->handle.device_id; + int num_devices = m->handle.num_devices; + int device_id = m->handle.device_id; ncclComm_t ncclComm = m->handle.ncclComm; DataType dtype = input.data_type; - // tensorrt_llm::AllReduceStrategyType strategy = - // tensorrt_llm::SelectImplementation( - // num_elements * ((get_bits(dtype) + 7) / 8), num_devices); + tensorrt_llm::AllReduceStrategyType strategy = + tensorrt_llm::SelectImplementation( + num_elements * ((get_bits(dtype) + 7) / 8), num_devices); + + if (strategy == tensorrt_llm::AllReduceStrategyType::RING || + !CanApplyCustomAllReduce(num_elements, dtype)) { + // Dispatch to nccl AllReduce if the customized all-reduce cannot apply. + ncclDataType_t nccl_data_type = ff_to_nccl_datatype(dtype); + runtime->concurrent_task_barrier(ctx); + checkNCCL(ncclAllReduce(input.ptr, + output.ptr, + num_elements, + nccl_data_type, + ncclSum, + ncclComm, + stream)); + runtime->concurrent_task_barrier(ctx); + return; + } - // if (strategy == tensorrt_llm::AllReduceStrategyType::RING || - // !CanApplyCustomAllReduce(num_elements, dtype)) { - // Dispatch to nccl AllReduce if the customized all-reduce cannot apply. - ncclDataType_t nccl_data_type = ff_to_nccl_datatype(dtype); - runtime->concurrent_task_barrier(ctx); - checkNCCL(ncclAllReduce(input.ptr, - output.ptr, - num_elements, - nccl_data_type, - ncclSum, - ncclComm, - stream)); - runtime->concurrent_task_barrier(ctx); - // return; - // } - - // // Initialize the all-reduce kernel arguments. - // tensorrt_llm::AllReduceParams params; - // params.ranks_per_node = num_devices; - // params.rank = device_id; - // params.local_rank = device_id; - // CommunicationBuffer *comm_buffer = - // get_or_create_comm_buffer(ctx, - // runtime, - // m, - // num_devices, - // device_id, - // ncclComm, - // const_cast(input.ptr), - // stream); - // params.barrier_flag = ++(*comm_buffer->barrier_flag); - // for (int i = 0; i < num_devices; ++i) { - // params.peer_comm_buffer_ptrs[i] = comm_buffer->comm_ptrs[i]; - // } - // for (int i = 0; i < num_devices; ++i) { - // params.peer_barrier_ptrs_in[i] = - // reinterpret_cast(comm_buffer->barrier_in[i]); - // } - // for (int i = 0; i < num_devices; ++i) { - // params.peer_barrier_ptrs_out[i] = - // reinterpret_cast(comm_buffer->barrier_out[i]); - // } - - // if (!CanApplyTwoShotAllReduce(num_elements, dtype, num_devices)) { - // // Two-shot all-reduce does not support this case. - // // So we fallback to the one-shot strategy. - // strategy = tensorrt_llm::AllReduceStrategyType::ONESHOT; - // } - - // runtime->concurrent_task_barrier(ctx); - // tensorrt_llm::customAllReduce( - // params, output.ptr, num_elements, dtype, strategy, stream); - // runtime->concurrent_task_barrier(ctx); + // Initialize the all-reduce kernel arguments. + tensorrt_llm::AllReduceParams params; + params.ranks_per_node = num_devices; + params.rank = device_id; + params.local_rank = device_id; + CommunicationBuffer *comm_buffer = + get_or_create_comm_buffer(m, + num_devices, + device_id, + ncclComm, + const_cast(input.ptr), + stream); + params.barrier_flag = ++(*comm_buffer->barrier_flag); + for (int i = 0; i < num_devices; ++i) { + params.peer_comm_buffer_ptrs[i] = comm_buffer->comm_ptrs[i]; + } + for (int i = 0; i < num_devices; ++i) { + params.peer_barrier_ptrs_in[i] = + reinterpret_cast(comm_buffer->barrier_in[i]); + } + for (int i = 0; i < num_devices; ++i) { + params.peer_barrier_ptrs_out[i] = + reinterpret_cast(comm_buffer->barrier_out[i]); + } + + if (!CanApplyTwoShotAllReduce(num_elements, dtype, num_devices)) { + // Two-shot all-reduce does not support this case. + // So we fallback to the one-shot strategy. + strategy = tensorrt_llm::AllReduceStrategyType::ONESHOT; + } + + tensorrt_llm::customAllReduce( + params, output.ptr, num_elements, dtype, strategy, stream); } -void forward_kernel_wrapper(Legion::Context ctx, - Legion::Runtime *runtime, +void forward_kernel_wrapper(Context ctx, + Runtime *runtime, AllReduceMeta const *m, GenericTensorAccessorR const &input, GenericTensorAccessorW const &output) { diff --git a/src/utils/communication_buffer.cu b/src/utils/communication_buffer.cu index 83b0385a35..cd6cc0db47 100644 --- a/src/utils/communication_buffer.cu +++ b/src/utils/communication_buffer.cu @@ -23,9 +23,7 @@ // For the i-th pointer, if i is the worker id of the given device, // then the returned i-th ptr_group is the local pointer, // or otherwise it is an peer memory pointer from the remote device. -std::vector create_peer_ptr_group(Legion::Context ctx, - Legion::Runtime *runtime, - int num_devices, +std::vector create_peer_ptr_group(int num_devices, int device_id, ncclComm_t ncclComm, void *allgather_src, @@ -48,14 +46,12 @@ std::vector create_peer_ptr_group(Legion::Context ctx, cudaMemcpyHostToDevice, stream)); - runtime->concurrent_task_barrier(ctx); checkNCCL(ncclAllGather(allgather_src, allgather_dst, sizeof(void *), ncclChar, ncclComm, stream)); - runtime->concurrent_task_barrier(ctx); std::vector peer_pointers(num_devices); checkCUDA(cudaMemcpyAsync(peer_pointers.data(), @@ -89,9 +85,7 @@ void free_peer_ptr_group(std::vector ptr_group, // all-gathering peer pointers across devices. The size of allgather_src should // be sizeof(void*), and the size of allgather_dst should be sizeof(void*) * // num_devices. -CommunicationBuffer *create_comm_buf_with_local_ptr(Legion::Context ctx, - Legion::Runtime *runtime, - int num_devices, +CommunicationBuffer *create_comm_buf_with_local_ptr(int num_devices, int device_id, ncclComm_t ncclComm, void *allgather_src, @@ -106,27 +100,21 @@ CommunicationBuffer *create_comm_buf_with_local_ptr(Legion::Context ctx, comm_buf->num_devices = num_devices; comm_buf->device_id = device_id; comm_buf->local_ptr = local_ptr; - comm_buf->comm_ptrs = create_peer_ptr_group(ctx, - runtime, - num_devices, + comm_buf->comm_ptrs = create_peer_ptr_group(num_devices, device_id, ncclComm, allgather_src, allgather_dst, local_ptr, stream); - comm_buf->barrier_in = create_peer_ptr_group(ctx, - runtime, - num_devices, + comm_buf->barrier_in = create_peer_ptr_group(num_devices, device_id, ncclComm, allgather_src, allgather_dst, barrier_in_ptr, stream); - comm_buf->barrier_out = create_peer_ptr_group(ctx, - runtime, - num_devices, + comm_buf->barrier_out = create_peer_ptr_group(num_devices, device_id, ncclComm, allgather_src, From 76df177dea6c9f0c6f45537af201664309533b21 Mon Sep 17 00:00:00 2001 From: fruitea Date: Sat, 16 Nov 2024 00:27:12 -0800 Subject: [PATCH 4/5] chore: minor --- src/runtime/request_manager.cc | 39 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/runtime/request_manager.cc b/src/runtime/request_manager.cc index 4b68367543..d2ddf6f349 100644 --- a/src/runtime/request_manager.cc +++ b/src/runtime/request_manager.cc @@ -500,19 +500,19 @@ RequestManager::RequestGuid request.tokens.push_back(bos_token_id); } std::vector tokens = this->tokenizer_->Encode(req.prompt); - // for (int i = 0; i < tokens.size(); i++) { - // std::cout << "[" << i << "]" << tokens.at(i) << "\n"; - // } - // std::cout << "[slo ratio] " << req.slo_ratio << std::endl; + for (int i = 0; i < tokens.size(); i++) { + std::cout << "[" << i << "]" << tokens.at(i) << "\n"; + } + std::cout << "[slo ratio] " << req.slo_ratio << std::endl; request.tokens.insert(request.tokens.end(), tokens.begin(), tokens.end()); request.set_slo_ratio(req.slo_ratio); if (get_num_ssms() == 0) { - // std::cout << "No small speculative model registered, using incremental " - // "decoding." - // << std::endl; + std::cout << "No small speculative model registered, using incremental " + "decoding." + << std::endl; } else { - // std::cout << "Num of SSMs: " << get_num_ssms() << std::endl; + std::cout << "Num of SSMs: " << get_num_ssms() << std::endl; assert(get_num_ssms() == 1 && "Only one SSM is supported now."); init_token_tree(request.guid); } @@ -762,8 +762,6 @@ void RequestManager::request_complete_clean_up(int batch_index) { // } // std::string output = // this->tokenizer_->Decode(std::vector(bos_it, eos_it)); - std::string output = this->tokenizer_->Decode(request.tokens); - { std::lock_guard const lock(request_result_mutex); request_generation_results[guid].output_tokens = request.tokens; @@ -786,12 +784,13 @@ void RequestManager::request_complete_clean_up(int batch_index) { trigger_request_completion_future(guid); - std::cout << "Request " << guid << " completed" << std::endl; - // std::cout << "" << output; - // if (eos_rit != request.tokens.rend()) { - // std::cout << ""; - // } - // std::cout << std::endl << std::endl; + std::string output = this->tokenizer_->Decode(request.tokens); + std::cout << "Request " << guid << " completed: " << std::endl; + std::cout << "" << output; + if (is_eos_token(request.tokens.back())) { + std::cout << ""; + } + std::cout << std::endl << std::endl; { RequestProfileInfo profile_info = profiling_requests[guid]; @@ -2424,10 +2423,10 @@ std::vector for (size_t i = 0; i < requests.size(); i++) { requests[i].slo_ratio = emission_machine.sample_slo_ratio(); requests[i].emission_time_ms = emission_machine.get_elapsed_time_ms(); - // printf("Prompt[%ld] with slo %.3f: %s\n", - // i, - // requests[i].slo_ratio, - // requests[i].prompt.c_str()); + printf("Prompt[%ld] with slo %.3f: %s\n", + i, + requests[i].slo_ratio, + requests[i].prompt.c_str()); RequestManager::RequestGuid guid = rm->register_new_request(requests[i]); if (guid != RequestManager::INVALID_GUID) { guids.push_back(guid); From 6c3bebca8e12c1c50e7aaafdc8d8bbc051b49c0d Mon Sep 17 00:00:00 2001 From: fruitea Date: Sat, 16 Nov 2024 02:16:06 -0800 Subject: [PATCH 5/5] chore: minor --- src/runtime/request_manager.cc | 39 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/runtime/request_manager.cc b/src/runtime/request_manager.cc index d2ddf6f349..66a95b3eda 100644 --- a/src/runtime/request_manager.cc +++ b/src/runtime/request_manager.cc @@ -1875,7 +1875,6 @@ bool RequestManager::update_ssm_inference_results( profiling_requests[guid].ssm_decoding_steps++; if (current_ssm_step == ssm_tree_depth) { - assert(profiling_requests[guid].ssm_decoding_steps % ssm_tree_depth == 0); profiling_requests[guid].speculation_start_timestamp = profiling.ssm_step_start; profiling_requests[guid].speculation_end_timestamp = @@ -2728,6 +2727,25 @@ void RequestManager::terminate_background_server() { for (int num_tokens : profiling.generated_tokens_per_step) { total_tokens += num_tokens; } + + if (profiling_requests.size() != all_requests.size()) { + std::cerr << "profiling_requests.size()=" << profiling_requests.size() + << " != all_requests.size()=" << all_requests.size() + << std::endl; + } + assert(profiling_requests.size() == all_requests.size()); + str += "\nDecoding Steps: "; + for (auto const &profiling_info : profiling_requests) { + int request_id = profiling_info.first; + Request &request = all_requests[request_id]; + str += "Request " + std::to_string(request_id) + ": "; + str += std::to_string(profiling_info.second.llm_decoding_steps); + str += "/"; + str += std::to_string(request.decode_length()); + float speedup = (float)request.decode_length() / + profiling_info.second.llm_decoding_steps; + str += " " + std::to_string(speedup) + "\n"; + } str += "\n total_time_ms(" + std::to_string(total_time / 1000.0) + ")"; str += "\n total_requests(" + std::to_string(total_requests) + "/" + std::to_string(all_requests.size()) + ")"; @@ -2878,25 +2896,6 @@ void RequestManager::terminate_background_server() { goodput_str += ")"; str += goodput_str; - if (profiling_requests.size() != all_requests.size()) { - std::cerr << "profiling_requests.size()=" << profiling_requests.size() - << " != all_requests.size()=" << all_requests.size() - << std::endl; - } - assert(profiling_requests.size() == all_requests.size()); - str += "\nDecoding Steps: "; - for (auto const &profiling_info : profiling_requests) { - int request_id = profiling_info.first; - Request &request = all_requests[request_id]; - str += "Request " + std::to_string(request_id) + ": "; - str += std::to_string(profiling_info.second.llm_decoding_steps); - str += "/"; - str += std::to_string(request.decode_length()); - float speedup = (float)request.decode_length() / - profiling_info.second.llm_decoding_steps; - str += " " + std::to_string(speedup) + "\n"; - } - write_to_output_file("", str); background_server_status = TERMINATED; request_queue_cv.notify_all();