{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [], "authorship_tag": "ABX9TyPq8j8wgw7Z2KyoosDpBmxG", "include_colab_link": true }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "view-in-github", "colab_type": "text" }, "source": [ "\"Open" ] }, { "cell_type": "markdown", "source": [ "# 从零搭建LLM调度器\n", "\n", "Build an LLM Scheduler from Scratch\n", "\n", "Author: kaiyuan\n", "\n", "Email: kyxie@zju.edu.cn" ], "metadata": { "id": "kEygK8XV2i7U" } }, { "cell_type": "markdown", "source": [ "# 1 输入与生成\n", "## 1.1 从prompts到tokens的转换\n", "\n", "方式1:使用transformers模块的AutoTokenizer" ], "metadata": { "id": "KFiHc6CANch_" } }, { "cell_type": "code", "source": [ "# 定义tokenizer:\n", "from transformers import AutoTokenizer\n", "\n", "tokenizer = AutoTokenizer.from_pretrained(\"Qwen/Qwen3-0.6B\", use_fast=True)\n", "prompts = [\n", " \"hi, I'm kaiyuan\",\n", " \"Do you subscribe InfraTech?\",\n", "]\n", "prompts = [\n", " tokenizer.apply_chat_template(\n", " [{\"role\": \"user\", \"content\": prompt}],\n", " tokenize=False,\n", " add_generation_prompt=True,\n", " )\n", " for prompt in prompts\n", "]\n", "for prompt in prompts:\n", " print(tokenizer.encode(prompt))" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "TRP_EtyJKZ7g", "outputId": "8c861637-984a-4e75-8c42-6e20e1f01f97" }, "execution_count": 1, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.12/dist-packages/huggingface_hub/utils/_auth.py:94: UserWarning: \n", "The secret `HF_TOKEN` does not exist in your Colab secrets.\n", "To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n", "You will be able to reuse this secret in all of your notebooks.\n", "Please note that authentication is recommended but still optional to access public models or datasets.\n", " warnings.warn(\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "[151644, 872, 198, 6023, 11, 358, 2776, 595, 2143, 88, 10386, 151645, 198, 151644, 77091, 198]\n", "[151644, 872, 198, 5404, 498, 17963, 14921, 956, 34097, 30, 151645, 198, 151644, 77091, 198]\n" ] } ] }, { "cell_type": "markdown", "source": [ "方式2: 构建一个随机整数输出,充当tokens。" ], "metadata": { "id": "Ba_lpLReNP33" } }, { "cell_type": "code", "source": [ "import numpy as np\n", "np.random.seed(0)\n", "\n", "def generate_random_int_tokens(min_len: int = 1, max_len: int = 10, min_val: int = 1, max_val: int = 999):\n", " \"\"\"\n", " 生成一个包含随机整数的数组。\n", "\n", " Args:\n", " min_len (int): 数组的最小长度。\n", " max_len (int): 数组的最大长度。\n", " min_val (int): 数组中整数的最小值(包含)。\n", " max_val (int): 数组中整数的最大值(包含)。\n", "\n", " Returns:\n", " list: 包含随机整数的数组。\n", " \"\"\"\n", " if min_len > max_len:\n", " raise ValueError(\"min_len must be less than or equal to max_len\")\n", " if min_val > max_val:\n", " raise ValueError(\"min_val must be less than or equal to max_val\")\n", "\n", " array_length = np.random.randint(min_len, max_len + 1)\n", " random_array = [np.random.randint(min_val, max_val + 1) for _ in range(array_length)]\n", " return random_array\n", "\n", "\n", "default_array = generate_random_int_tokens()\n", "print(default_array)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "_r2vx8qfLdNU", "outputId": "01e076da-c5a8-4930-eb6a-e2e06d7334e3" }, "execution_count": 2, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "[193, 836, 764, 708, 360, 10]\n" ] } ] }, { "cell_type": "markdown", "source": [ "## 1.2 构造一个模拟的LLM\n", "构建一个假的模型运算,模拟输入一个提示词,生成一个token。" ], "metadata": { "id": "1QqW-gWbOkJI" } }, { "cell_type": "code", "source": [ "def run_fake_model(seqs, max_len: int = 15, min_val: int = -1, max_val: int = 999, eos: int=-1):\n", " token_ids = [eos if len(seq) >= max_len else np.random.randint(min_val, max_val + 1) for seq in seqs]\n", " return token_ids" ], "metadata": { "id": "CfvWIh-jOjC7" }, "execution_count": 3, "outputs": [] }, { "cell_type": "code", "source": [ "# 测试:\n", "seqs = [[536, 332, 844, 933, 736, 476, 87], [1000]]\n", "print(run_fake_model(seqs))" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "5_gg-JHK6d_R", "outputId": "d0e2b0fe-6139-41bc-e711-bc64a9171510" }, "execution_count": 4, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "[722, 276]\n" ] } ] }, { "cell_type": "markdown", "source": [ "\n", "## 2 辅助函数&类\n", "\n", "1、配置文件:" ], "metadata": { "id": "qw4-jTlHTCWi" } }, { "cell_type": "code", "source": [ "import os\n", "from dataclasses import dataclass\n", "\n", "\n", "@dataclass\n", "class Config:\n", " model: str = \"dummy\"\n", " max_num_batched_tokens: int = 16384\n", " max_num_seqs: int = 512\n", " max_model_len: int = 4096\n", " gpu_memory_utilization: float = 0.9\n", " tensor_parallel_size: int = 1\n", " enforce_eager: bool = False\n", " eos: int = -1\n", " kvcache_block_size: int = 256\n", " num_kvcache_blocks: int = -1\n", "\n", " def __post_init__(self):\n", " assert self.kvcache_block_size % 256 == 0\n", " assert 1 <= self.tensor_parallel_size <= 8\n", " assert self.max_num_batched_tokens >= self.max_model_len" ], "metadata": { "id": "iyNfmYE0TCqd" }, "execution_count": 5, "outputs": [] }, { "cell_type": "markdown", "source": [ "2、采样参数:" ], "metadata": { "id": "JnxgFbf-Q8Hq" } }, { "cell_type": "code", "source": [ "from dataclasses import dataclass\n", "\n", "\n", "@dataclass\n", "class SamplingParams:\n", " temperature: float = 1.0\n", " max_tokens: int = 64\n", " ignore_eos: bool = False\n" ], "metadata": { "id": "QZauuOffQ8e2" }, "execution_count": 6, "outputs": [] }, { "cell_type": "markdown", "source": [ "3、 请求序列\n", "\n", "用Sequence类承载单个请求的相关信息\n", "* 序列tokens数据,请求状态\n", "* KV cache blocks的使用情况" ], "metadata": { "id": "v2uVnb99SGLV" } }, { "cell_type": "code", "source": [ "from copy import copy\n", "from enum import Enum, auto\n", "from itertools import count\n", "\n", "\n", "class SequenceStatus(Enum):\n", " WAITING = auto()\n", " RUNNING = auto()\n", " FINISHED = auto()\n", "\n", "\n", "class Sequence:\n", " block_size = 256\n", " counter = count()\n", "\n", " def __init__(self, token_ids: list[int], sampling_params = SamplingParams()):\n", " self.seq_id = next(Sequence.counter)\n", " self.status = SequenceStatus.WAITING\n", " self.token_ids = copy(token_ids)\n", " self.last_token = token_ids[-1]\n", " self.num_tokens = len(self.token_ids)\n", " self.num_prompt_tokens = len(token_ids)\n", " self.num_cached_tokens = 0\n", " self.block_table = []\n", " self.temperature = sampling_params.temperature\n", " self.max_tokens = sampling_params.max_tokens\n", " self.ignore_eos = sampling_params.ignore_eos\n", "\n", " def __len__(self):\n", " return self.num_tokens\n", "\n", " def __getitem__(self, key):\n", " return self.token_ids[key]\n", "\n", " @property\n", " def is_finished(self):\n", " return self.status == SequenceStatus.FINISHED\n", "\n", " @property\n", " def num_completion_tokens(self):\n", " return self.num_tokens - self.num_prompt_tokens\n", "\n", " @property\n", " def prompt_token_ids(self):\n", " return self.token_ids[:self.num_prompt_tokens]\n", "\n", " @property\n", " def completion_token_ids(self):\n", " return self.token_ids[self.num_prompt_tokens:]\n", "\n", " @property\n", " def num_cached_blocks(self):\n", " return self.num_cached_tokens // self.block_size\n", "\n", " @property\n", " def num_blocks(self):\n", " return (self.num_tokens + self.block_size - 1) // self.block_size\n", "\n", " @property\n", " def last_block_num_tokens(self):\n", " return self.num_tokens - (self.num_blocks - 1) * self.block_size\n", "\n", " def block(self, i):\n", " assert 0 <= i < self.num_blocks\n", " return self.token_ids[i*self.block_size: (i+1)*self.block_size]\n", "\n", " def append_token(self, token_id: int):\n", " self.token_ids.append(token_id)\n", " self.last_token = token_id\n", " self.num_tokens += 1\n", "\n", " def __getstate__(self):\n", " return (self.num_tokens, self.num_prompt_tokens, self.num_cached_tokens, self.block_table,\n", " self.token_ids if self.num_completion_tokens == 0 else self.last_token)\n", "\n", " def __setstate__(self, state):\n", " self.num_tokens, self.num_prompt_tokens, self.num_cached_tokens, self.block_table = state[:-1]\n", " if self.num_completion_tokens == 0:\n", " self.token_ids = state[-1]\n", " else:\n", " self.last_token = state[-1]" ], "metadata": { "id": "T9kxwl4RSFeX" }, "execution_count": 7, "outputs": [] }, { "cell_type": "markdown", "source": [ "4、KV cache管理器\n", "\n", "* paged attention原理管理KV cache。\n", "* 以Block为单位管理KV cache,每个Block包含若干tokens cache空间。\n", "* 统一由BlockManager管理。" ], "metadata": { "id": "9EyzPu2FTtzP" } }, { "cell_type": "code", "source": [ "from collections import deque\n", "import xxhash\n", "import numpy as np\n", "\n", "class Block:\n", "\n", " def __init__(self, block_id):\n", " self.block_id = block_id\n", " self.ref_count = 0\n", " self.hash = -1\n", " self.token_ids = []\n", "\n", " def update(self, hash: int, token_ids: list[int]):\n", " self.hash = hash\n", " self.token_ids = token_ids\n", "\n", " def reset(self):\n", " self.ref_count = 1\n", " self.hash = -1\n", " self.token_ids = []\n", "\n", "\n", "class BlockManager:\n", "\n", " def __init__(self, num_blocks: int, block_size: int):\n", " self.block_size = block_size\n", " self.blocks: list[Block] = [Block(i) for i in range(num_blocks)]\n", " self.hash_to_block_id: dict[int, int] = dict()\n", " self.free_block_ids: deque[int] = deque(range(num_blocks))\n", " self.used_block_ids: set[int] = set()\n", "\n", " @classmethod\n", " def compute_hash(cls, token_ids: list[int], prefix: int = -1):\n", " h = xxhash.xxh64()\n", " if prefix != -1:\n", " h.update(prefix.to_bytes(8, \"little\"))\n", " h.update(np.array(token_ids).tobytes())\n", " return h.intdigest()\n", "\n", " def _allocate_block(self, block_id: int) -> Block:\n", " block = self.blocks[block_id]\n", " assert block.ref_count == 0\n", " block.reset()\n", " self.free_block_ids.remove(block_id)\n", " self.used_block_ids.add(block_id)\n", " return self.blocks[block_id]\n", "\n", " def _deallocate_block(self, block_id: int) -> Block:\n", " assert self.blocks[block_id].ref_count == 0\n", " self.used_block_ids.remove(block_id)\n", " self.free_block_ids.append(block_id)\n", "\n", " def can_allocate(self, seq: Sequence) -> bool:\n", " return len(self.free_block_ids) >= seq.num_blocks\n", "\n", " def allocate(self, seq: Sequence):\n", " assert not seq.block_table\n", " h = -1\n", " cache_miss = False\n", " for i in range(seq.num_blocks):\n", " token_ids = seq.block(i)\n", " h = self.compute_hash(token_ids, h) if len(token_ids) == self.block_size else -1\n", " block_id = self.hash_to_block_id.get(h, -1)\n", " if block_id == -1 or self.blocks[block_id].token_ids != token_ids:\n", " cache_miss = True\n", " if cache_miss:\n", " block_id = self.free_block_ids[0]\n", " block = self._allocate_block(block_id)\n", " else:\n", " seq.num_cached_tokens += self.block_size\n", " if block_id in self.used_block_ids:\n", " block = self.blocks[block_id]\n", " block.ref_count += 1\n", " else:\n", " block = self._allocate_block(block_id)\n", " if h != -1:\n", " block.update(h, token_ids)\n", " self.hash_to_block_id[h] = block_id\n", " seq.block_table.append(block_id)\n", "\n", " def deallocate(self, seq: Sequence):\n", " for block_id in reversed(seq.block_table):\n", " block = self.blocks[block_id]\n", " block.ref_count -= 1\n", " if block.ref_count == 0:\n", " self._deallocate_block(block_id)\n", " seq.num_cached_tokens = 0\n", " seq.block_table.clear()\n", "\n", " def can_append(self, seq: Sequence) -> bool:\n", " return len(self.free_block_ids) >= (len(seq) % self.block_size == 1)\n", "\n", " def may_append(self, seq: Sequence):\n", " block_table = seq.block_table\n", " last_block = self.blocks[block_table[-1]]\n", " if len(seq) % self.block_size == 1:\n", " assert last_block.hash != -1\n", " block_id = self.free_block_ids[0]\n", " self._allocate_block(block_id)\n", " block_table.append(block_id)\n", " elif len(seq) % self.block_size == 0:\n", " assert last_block.hash == -1\n", " token_ids = seq.block(seq.num_blocks-1)\n", " prefix = self.blocks[block_table[-2]].hash if len(block_table) > 1 else -1\n", " h = self.compute_hash(token_ids, prefix)\n", " last_block.update(h, token_ids)\n", " self.hash_to_block_id[h] = last_block.block_id\n", " else:\n", " assert last_block.hash == -1\n" ], "metadata": { "id": "xjq4-hs4TuGF" }, "execution_count": 8, "outputs": [] }, { "cell_type": "markdown", "source": [ "## 3 定义Scheduler\n", "\n", "scheduler基本功能:\n", "* 支持Continuous-batching\n", "* 可以控制prefill和decode的执行优先级,默认prefill优先;\n", "* decode具备资源不足抢占功能\n", "\n", "不考虑prefill和decode混合调度执行。deocde优先时,为非Continuous-batching状态。" ], "metadata": { "id": "GwCJN4zBT4Fw" } }, { "cell_type": "code", "source": [ "from collections import deque\n", "\n", "class Scheduler:\n", "\n", " def __init__(self, config: Config):\n", " self.max_num_seqs = config.max_num_seqs\n", " self.max_num_batched_tokens = config.max_num_batched_tokens\n", " self.eos = config.eos\n", " self.block_manager = BlockManager(config.num_kvcache_blocks, config.kvcache_block_size)\n", " self.waiting: deque[Sequence] = deque()\n", " self.running: deque[Sequence] = deque()\n", " self.num_seqs = 0\n", " self.num_batched_tokens = 0\n", "\n", " def is_finished(self):\n", " return not self.waiting and not self.running\n", "\n", " def add(self, seq: Sequence):\n", " self.waiting.append(seq)\n", "\n", " def prefill(self):\n", " scheduled_seqs = []\n", " while self.waiting and self.num_seqs < self.max_num_seqs:\n", " seq = self.waiting[0]\n", " if self.num_batched_tokens + len(seq) > self.max_num_batched_tokens or not self.block_manager.can_allocate(seq):\n", " break\n", " self.num_seqs += 1\n", " self.block_manager.allocate(seq)\n", " self.num_batched_tokens += len(seq) - seq.num_cached_tokens\n", " seq.status = SequenceStatus.RUNNING\n", " self.waiting.popleft()\n", " self.running.append(seq)\n", " scheduled_seqs.append(seq)\n", " return scheduled_seqs, True\n", "\n", " def decode(self):\n", " scheduled_seqs = []\n", " while self.running and self.num_seqs < self.max_num_seqs:\n", " seq = self.running.popleft()\n", " while not self.block_manager.can_append(seq):\n", " if self.running:\n", " self.preempt(self.running.pop())\n", " else:\n", " self.preempt(seq)\n", " break\n", " else:\n", " self.num_seqs += 1\n", " self.block_manager.may_append(seq)\n", " scheduled_seqs.append(seq)\n", " if scheduled_seqs:\n", " self.running.extendleft(reversed(scheduled_seqs))\n", " return scheduled_seqs, False\n", "\n", " def preempt(self, seq: Sequence):\n", " seq.status = SequenceStatus.WAITING\n", " self.block_manager.deallocate(seq)\n", " self.waiting.appendleft(seq)\n", "\n", " def schedule(self, prefill_first=True) -> tuple[list[Sequence], bool]:\n", " scheduled_seqs = []\n", " self.num_seqs = 0\n", " self.num_batched_tokens = 0\n", " is_prefill = True\n", "\n", " if prefill_first:\n", " first_call, second_call = self.prefill, self.decode\n", " else:\n", " first_call, second_call = self.decode, self.prefill\n", "\n", " scheduled_seqs, is_prefill = first_call()\n", " if scheduled_seqs:\n", " return scheduled_seqs, is_prefill\n", "\n", " scheduled_seqs, is_prefill = second_call()\n", " if scheduled_seqs:\n", " return scheduled_seqs, is_prefill\n", " assert scheduled_seqs\n", "\n", " def postprocess(self, seqs: list[Sequence], token_ids: list[int]) -> list[bool]:\n", " for seq, token_id in zip(seqs, token_ids):\n", " seq.append_token(token_id)\n", " if (not seq.ignore_eos and token_id == self.eos) or seq.num_completion_tokens == seq.max_tokens:\n", " seq.status = SequenceStatus.FINISHED\n", " self.block_manager.deallocate(seq)\n", " self.running.remove(seq)\n" ], "metadata": { "id": "M25jcqd4T4TZ" }, "execution_count": 9, "outputs": [] }, { "cell_type": "markdown", "source": [ "scheduler的测试" ], "metadata": { "id": "paBJUgN3XkVl" } }, { "cell_type": "code", "source": [ "\n", "config = Config()\n", "config.num_kvcache_blocks = 100\n", "config.max_num_seqs = 3 # 最多运行多少个请求\n", "config.max_model_len = 15 # 单条请求长度\n", "\n", "\n", "sampling_params = SamplingParams(temperature=0.6, max_tokens=256)\n", "scheduler = Scheduler(config)\n", "\n", "\n", "# 增加第一个请求\n", "token_ids = tokenizer.encode(\"Do you subscribe InfraTech?\")\n", "seq = Sequence(token_ids, sampling_params)\n", "scheduler.add(seq)\n", "\n", "# 增加第二个请求\n", "token_ids = tokenizer.encode(\"hi, I'm kaiyuan\")\n", "seq = Sequence(token_ids, sampling_params)\n", "scheduler.add(seq)\n", "\n", "# 打印输入请求情况\n", "print(\"scheduler waiting queue: \")\n", "for id, seq in enumerate(scheduler.waiting):\n", " print(f\"id:{id} seq:{seq.token_ids}\")\n", "\n", "# 测试调度与生成:\n", "print(\"\\nrunning: \")\n", "while not scheduler.is_finished():\n", " seqs, is_prefill = scheduler.schedule()\n", " token_ids = run_fake_model(seqs, config.max_model_len)\n", " scheduler.postprocess(seqs, token_ids)\n", " for id, seq in enumerate(seqs):\n", " print(f\"id:{id} seq:{seq.token_ids}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "xF7-xqCbXjy5", "outputId": "07e878ba-726f-42ea-8d55-e310c90bb2cc" }, "execution_count": 10, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "scheduler waiting queue: \n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386]\n", "\n", "running: \n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69, 599]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471, 395]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69, 599, 313]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471, 395, 704]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69, 599, 313, 485]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471, 395, 704, 550]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69, 599, 313, 485, 86]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471, 395, 704, 550, 173]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69, 599, 313, 485, 86, 599]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471, 395, 704, 550, 173, 848]\n", "id:1 seq:[6023, 11, 358, 2776, 595, 2143, 88, 10386, 803, 69, 599, 313, 485, 86, 599, -1]\n", "id:0 seq:[5404, 498, 17963, 14921, 956, 34097, 30, 753, 598, 471, 395, 704, 550, 173, 848, -1]\n" ] } ] }, { "cell_type": "markdown", "source": [ "## 4 构造一个Engine类\n", "\n", "* 模拟LLM推理过程\n", "* 返回在执行队列和等待队列的情况" ], "metadata": { "id": "zwXlAh2Ve_xK" } }, { "cell_type": "code", "source": [ "import queue\n", "\n", "\n", "class Engine():\n", " def __init__(self, init_reqs=5, totoal_reqs=8, add_reqs_step=15,\n", " kvcache_block_size=10, num_kvcache_blocks=100,\n", " max_num_seqs=3, max_model_len=15, prefill_first=True):\n", "\n", " self.reqs_q = queue.Queue()\n", " self.add_reqs_step = add_reqs_step\n", " for _ in range(totoal_reqs):\n", " prompt = generate_random_int_tokens()\n", " self.reqs_q.put(prompt)\n", "\n", " config = Config()\n", " config.num_kvcache_blocks = num_kvcache_blocks\n", " config.kvcache_block_size = kvcache_block_size\n", " config.max_num_seqs = max_num_seqs # 最多运行多少个请求\n", " config.max_model_len = max_model_len # 单条请求长度\n", " Sequence.counter = count() # 重置计数\n", "\n", " self.sampling_params = SamplingParams(temperature=0.6, max_tokens=256)\n", " self.scheduler = Scheduler(config)\n", " self.prefill_first = prefill_first\n", "\n", " # init scheduler\n", " for _ in range(init_reqs):\n", " prompt = self.reqs_q.get()\n", " seq = Sequence(prompt, sampling_params)\n", " self.scheduler.add(seq)\n", "\n", "\n", " def run_engine(self, steps=1):\n", " \"\"\"\n", " 返回在执行的队列和等待队列\n", " queue e.g.\n", " [{\n", " 'id': 5,\n", " 'data': [123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627]\n", " },]\n", " \"\"\"\n", "\n", " seqs = []\n", " if not self.scheduler.is_finished():\n", " seqs, is_prefill = self.scheduler.schedule(prefill_first=self.prefill_first)\n", " token_ids = run_fake_model(seqs, config.max_model_len)\n", " self.scheduler.postprocess(seqs, token_ids)\n", "\n", " while not self.reqs_q.empty() and steps > self.add_reqs_step:\n", " prompt = self.reqs_q.get()\n", " seq = Sequence(prompt, sampling_params)\n", " self.scheduler.add(seq)\n", "\n", " current_waiting = []\n", " executing = [{'id': seq.seq_id, 'data': seq.token_ids} for seq in seqs]\n", " running_seq_id = [seq.seq_id for seq in seqs]\n", " for seq in self.scheduler.waiting + self.scheduler.running:\n", " if seq.seq_id not in running_seq_id:\n", " current_waiting.append({'id': seq.seq_id, 'data': seq.token_ids})\n", "\n", " return executing, current_waiting" ], "metadata": { "id": "y61YYCMEo-xF" }, "execution_count": 11, "outputs": [] }, { "cell_type": "markdown", "source": [ "## 5 调度器队列可视化" ], "metadata": { "id": "CIDTUdivgFh_" } }, { "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "import matplotlib.animation as animation\n", "import matplotlib.patches as patches\n", "import numpy as np\n", "from collections import deque\n", "from IPython.display import HTML, display\n", "\n", "figsize=(9, 6)\n", "class AdvancedQueueVisualizer:\n", " def __init__(self, figsize=figsize):\n", " \"\"\"\n", " 高级队列可视化器,支持长数值和长数组\n", "\n", " 参数:\n", " - figsize: 图形大小\n", " \"\"\"\n", " # 创建图形\n", " self.fig, (self.ax_running, self.ax_waiting) = plt.subplots(2, 1, figsize=figsize)\n", "\n", " # 设置标题\n", " self.ax_running.set_title('EXECUTING QUEUE', fontsize=16, fontweight='bold', color='darkgreen', pad=15)\n", " self.ax_waiting.set_title('WAITING QUEUE', fontsize=16, fontweight='bold', color='darkorange', pad=15)\n", "\n", " # 设置坐标轴\n", " self.ax_running.set_xlim(-1, 17)\n", " self.ax_running.set_ylim(0, 5)\n", " self.ax_waiting.set_xlim(-1, 17)\n", " self.ax_waiting.set_ylim(0, 5)\n", "\n", " # 网格和边框\n", " for ax in [self.ax_running, self.ax_waiting]:\n", " ax.grid(True, alpha=0.2, linestyle='--')\n", " ax.tick_params(axis='both', which='major', labelsize=9)\n", "\n", " # 添加坐标轴标签\n", " self.ax_running.set_xlabel('Sequence', fontsize=12)\n", " self.ax_waiting.set_xlabel('Sequence', fontsize=12)\n", "\n", " # 存储图形元素\n", " self.elements = []\n", "\n", " # 颜色管理\n", " self.color_palette = [\n", " '#FF6B6B', '#4ECDC4', '#FFD166', '#06D6A0', '#118AB2',\n", " '#EF476F', '#9B5DE5', '#00BBF9', '#FF97B7', '#B5E48C',\n", " '#7209B7', '#F72585', '#3A0CA3', '#4361EE', '#4CC9F0'\n", " ]\n", " self.color_map = {} # request_id -> color\n", "\n", " # 统计信息\n", " self.frame_count = 0\n", "\n", " # 显示设置\n", " self.show_progress_bars = True\n", " self.compact_mode = False # 紧凑模式,显示更多元素\n", " self.max_request_display_length = 20 # 最多显示的数组长度\n", "\n", " def get_color(self, request_id):\n", " \"\"\"获取或创建数组颜色\"\"\"\n", " if request_id not in self.color_map:\n", " color_idx = request_id % len(self.color_palette)\n", " self.color_map[request_id] = self.color_palette[color_idx]\n", " return self.color_map[request_id]\n", "\n", " def format_number(self, num):\n", " \"\"\"格式化数字显示\"\"\"\n", " if isinstance(num, (int, np.integer)):\n", " if num == 0:\n", " return \"0\"\n", " elif abs(num) < 1000:\n", " return str(num)\n", " else:\n", " return str('...')\n", " elif isinstance(num, float):\n", " # 浮点数格式\n", " if abs(num) < 0.01 or abs(num) >= 10000:\n", " return f\"{num:.2e}\"\n", " else:\n", " return f\"{num:.2f}\"\n", " else:\n", " return str(num)\n", "\n", " def draw_request(self, ax, request_data, y_pos, is_running=True):\n", " \"\"\"绘制一个数组\"\"\"\n", " elements = []\n", " request_id = request_data.get('id', 0)\n", " data = request_data.get('data', [])\n", "\n", " # 如果数组太长,进行截断显示\n", " display_data = data\n", " if len(data) > self.max_request_display_length:\n", " # 只显示前后部分\n", " front_count = self.max_request_display_length // 2\n", " back_count = self.max_request_display_length - front_count - 1 # -1 给省略号留位置\n", " display_data = data[:front_count] + [None] + data[-back_count:]\n", "\n", " # 计算矩形参数\n", " if self.compact_mode:\n", " rect_width = 0.7\n", " rect_height = 0.5\n", " spacing = 0.1\n", " else:\n", " rect_width = 0.9\n", " rect_height = 0.6\n", " spacing = 0.15\n", "\n", " # 获取数组颜色\n", " color = self.get_color(request_id)\n", "\n", " # 绘制背景区域\n", " total_width = len(display_data) * (rect_width + spacing) - spacing + 0.4\n", " bg_rect = patches.Rectangle(\n", " (-0.2, y_pos - rect_height/2),\n", " total_width, rect_height,\n", " linewidth=1, edgecolor='gray',\n", " facecolor=color, alpha=0.1\n", " )\n", " ax.add_patch(bg_rect)\n", " elements.append(bg_rect)\n", "\n", " # 绘制每个元素\n", " for i, value in enumerate(display_data):\n", " # 计算位置\n", " x_pos = i * (rect_width + spacing)\n", "\n", " # 处理截断标记\n", " if value is None:\n", " # 绘制省略号\n", " ellipse = patches.Ellipse(\n", " (x_pos + rect_width/2, y_pos),\n", " rect_width * 0.6, rect_height * 0.3,\n", " facecolor='gray', alpha=0.5,\n", " edgecolor='none'\n", " )\n", " ax.add_patch(ellipse)\n", " elements.append(ellipse)\n", "\n", " # 添加省略号文本\n", " text = ax.text(\n", " x_pos + rect_width/2, y_pos,\n", " \"...\",\n", " ha='center', va='center',\n", " fontsize=8, fontweight='bold', color='darkgray'\n", " )\n", " elements.append(text)\n", " continue\n", "\n", " # 绘制矩形\n", " rect = patches.Rectangle(\n", " (x_pos, y_pos - rect_height/2),\n", " rect_width, rect_height,\n", " linewidth=2,\n", " edgecolor='darkblue' if is_running else 'gray',\n", " facecolor=color,\n", " alpha=0.8 if is_running else 0.6\n", " )\n", " ax.add_patch(rect)\n", " elements.append(rect)\n", "\n", " # 格式化数值显示\n", " formatted_value = self.format_number(value)\n", "\n", " # 根据数值长度调整字体大小\n", " fontsize = 9\n", " if len(str(formatted_value)) > 6:\n", " fontsize = 7\n", " elif len(str(formatted_value)) > 4:\n", " fontsize = 8\n", "\n", " # 添加数值文本\n", " text_color = 'white' if is_running else 'black'\n", " text = ax.text(\n", " x_pos + rect_width/2, y_pos,\n", " formatted_value,\n", " ha='center', va='center',\n", " fontsize=fontsize, fontweight='bold',\n", " color=text_color\n", " )\n", " elements.append(text)\n", "\n", " # 添加数组标签\n", " label_text = f\"ID:{request_id} (L:{len(data)})\"\n", " if is_running and self.show_progress_bars and len(data) > 0:\n", " # 添加进度条\n", " progress = min(1.0, len(data) / self.max_request_display_length)\n", " progress_width = total_width * progress\n", "\n", " progress_bar = patches.Rectangle(\n", " (-0.2, y_pos - rect_height/2 - 0.05),\n", " progress_width, 0.03,\n", " facecolor='green', alpha=0.6, edgecolor='none'\n", " )\n", " ax.add_patch(progress_bar)\n", " elements.append(progress_bar)\n", "\n", " label = ax.text(\n", " -0.5, y_pos, label_text,\n", " ha='right', va='center',\n", " fontsize=9,\n", " bbox=dict(boxstyle='round,pad=0.2', facecolor='white', alpha=0.8)\n", " )\n", " elements.append(label)\n", "\n", " return elements\n", "\n", " def update_display(self, running_data, waiting_data):\n", " \"\"\"\n", " 更新显示\n", "\n", " 参数:\n", " - running_data: EXECUTING队列数据,list of dict,每个dict包含'id'和'data'\n", " - waiting_data: WAITING队列数据,格式同上\n", " \"\"\"\n", " # 清除旧元素\n", " for elem in self.elements:\n", " elem.remove()\n", " self.elements = []\n", "\n", " # 更新统计\n", " self.frame_count += 1\n", "\n", " # 绘制RUNNING队列\n", " for i, arr in enumerate(running_data[:5]): # 最多显示5个\n", " y_pos = 4.5 - i * 1.2 # 调整垂直间距\n", " elements = self.draw_request(self.ax_running, arr, y_pos, is_running=True)\n", " self.elements.extend(elements)\n", "\n", " # 绘制WAITING队列\n", " for i, arr in enumerate(waiting_data[:5]): # 最多显示5个\n", " y_pos = 4.5 - i * 1.2 # 调整垂直间距\n", " elements = self.draw_request(self.ax_waiting, arr, y_pos, is_running=False)\n", " self.elements.extend(elements)\n", "\n", " # 更新标题\n", " running_count = len(running_data)\n", " waiting_count = len(waiting_data)\n", "\n", " self.ax_running.set_title(\n", " f'EXECUTING QUEUE: {running_count} requests (Frame: {self.frame_count})',\n", " fontsize=14, fontweight='bold', color='darkgreen'\n", " )\n", "\n", " self.ax_waiting.set_title(\n", " f'WAITING QUEUE: {waiting_count} requests',\n", " fontsize=14, fontweight='bold', color='darkorange'\n", " )\n", "\n", " # 如果有更多数组未显示,添加提示\n", " if len(running_data) > 5:\n", " self.ax_running.text(\n", " 0.5, -0.1, f\"+{len(running_data) - 5} more requests...\",\n", " ha='center', va='center',\n", " fontsize=9, color='gray',\n", " transform=self.ax_running.transAxes\n", " )\n", "\n", " if len(waiting_data) > 5:\n", " self.ax_waiting.text(\n", " 0.5, -0.1, f\"+{len(waiting_data) - 5} more requests...\",\n", " ha='center', va='center',\n", " fontsize=9, color='gray',\n", " transform=self.ax_waiting.transAxes\n", " )\n", "\n", " plt.tight_layout()\n", " return self.elements\n", "\n", " def show(self):\n", " \"\"\"显示图形\"\"\"\n", " plt.show()\n", "\n", "# 动画版本\n", "class AnimatedQueueVisualizer(AdvancedQueueVisualizer):\n", " def __init__(self, data_source_func=None, interval=500, frames=100, figsize=figsize):\n", " \"\"\"\n", " 动画版本\n", "\n", " 参数:\n", " - data_source_func: 数据源函数,返回(running_data, waiting_data)\n", " - interval: 动画间隔(ms)\n", " - frames: 动画帧数\n", " - figsize: 图形大小\n", " \"\"\"\n", " super().__init__(figsize)\n", "\n", " self.data_source_func = data_source_func\n", " self.interval = interval\n", " self.frames = frames\n", "\n", " # 初始显示\n", " if data_source_func:\n", " running_data, waiting_data = data_source_func(0)\n", " self.update_display(running_data, waiting_data)\n", "\n", " def animate_frame(self, frame_num):\n", " \"\"\"动画帧函数\"\"\"\n", " if self.data_source_func:\n", " running_data, waiting_data = self.data_source_func(frame_num)\n", " return self.update_display(running_data, waiting_data)\n", " return self.elements\n", "\n", " def create_animation(self):\n", " \"\"\"创建动画\"\"\"\n", " ani = animation.FuncAnimation(\n", " self.fig,\n", " self.animate_frame,\n", " frames=self.frames,\n", " interval=self.interval,\n", " blit=False\n", " )\n", " return ani\n", "\n", " def show_animation(self):\n", " \"\"\"在Jupyter中显示动画\"\"\"\n", " ani = self.create_animation()\n", " return HTML(ani.to_jshtml())\n" ], "metadata": { "id": "Cod2FRCAxtMl" }, "execution_count": 12, "outputs": [] }, { "cell_type": "code", "source": [ "print(\"静态显示示例:\")\n", "engine = Engine()\n", "viz = AdvancedQueueVisualizer()\n", "executing_data, waiting_data = engine.run_engine()\n", "viz.update_display(executing_data, waiting_data)\n", "viz.show()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 625 }, "id": "UK5AgzFgx5MM", "outputId": "201e2a0d-0cc4-47be-b75a-40ac5e09672b" }, "execution_count": 13, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "静态显示示例:\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "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bhyWL1/us85DDz0ERVGwc+dOTJs2DampqTCZTLjmmmtQWVnp1873338fw4cPR0JCAtLS0jB27Fj89NNPPut8//33OOmkk5CYmIjk5GRMmDABmzdvDpAkERG1NizsiIgoYuTk5ODPP//Epk2b6l3v0UcfxdVXX42ePXviP//5D2699Vb88ssvGDt2LEpLS93rvfnmm5gxYwbat2+Pp556CqNHj8b5558fsABsrF9//RVjx46FxWLBgw8+iMceewylpaU45ZRTsGbNGr/1J0+ejLKyMjz++OOYPHky5s2bhzlz5visM2fOHFx11VXQ6XR4+OGHMWfOHHTq1Am//vqre5333nsPEyZMQFJSEp588kncf//92LJlC8aMGeNXkBIRUSukEhERRYiffvpJ1Wq1qlarVUeOHKn+85//VH/88UfVZrO519m7d6+q1WrVRx991Od3N27cqMbFxbmX22w2tW3bturgwYNVq9XqXu+1115TAajjxo1zL3v77bdVAOqePXt8trl48WIVgLp48WJVVVXV6XSqPXv2VM8880zV6XS616usrFS7du2qnn766e5lDz74oApAvfbaa322eeGFF6oZGRnu+zt27FA1Go164YUXqg6Hw2dd13OUlZWpqamp6vTp030ez8vLU00mk99yIiJqfdhjR0REEeP000/HypUrcf7552P9+vV46qmncOaZZ6Jjx474+uuvAQBffPEFnE4nJk+ejMLCQvetffv26NmzJxYvXgwAWLt2LY4ePYobb7wRer3e/RzTpk2DyWRqVvtyc3OxY8cOXH755SgqKnI/d0VFBU499VT89ttvcDqdPr9z4403+tw/6aSTUFRUBIvFAgBYsGABnE4nHnjgAWg0vv8sK4oCAFi0aBFKS0sxZcoUn33WarUYMWKEe5+JiKj1igt3A4iIiLwNGzYMX3zxBWw2G9avX48vv/wS//3vf3HxxRe7CytVVdGzZ8+Av6/T6QAA+/btAwC/9XQ6Hbp169astu3YsQMAMHXq1KDrmM1mpKWlue937tzZ53HXYyUlJUhJScGuXbug0WjQr1+/Bp/3lFNOCfh4SkpK43aAiIhiFgs7IiKKSHq9HsOGDcOwYcPQq1cvXHPNNfj000/hdDqhKAq+//57aLVav99LSkpq8nO5esbqcjgcPvddvXFPP/00Bg8eHPB36j5/oDYCgNqE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oVAI69atwz/+8Q88+eSTuOaaa6KNlVIKPXv2bPD7MzIyAAC7du0CgHrbZWRk4PTTTz+p2rZu3QoAuOmmmxrdxufzITc3N/p1ly5dYh6vfaykpAQejwfbt2+HzWZD3759m33eiy++uMHHPR5PyyZARESWxcaOiIhMyW6345xzzsE555yDXr16YeLEiXjjjTeg6zo0TcOHH36ItLS0et/ncrla/Vy1Z8ZOFIlEYr6uPRv36KOPYsCAAQ1+z4nP31CNAKBasSh17fP+9a9/Rbt27eo9np7OH+dERKmOPwmIiMj0Bg0aBAA4cOAAunfvDqUUunXrhl69ejX6PV27dgVQc7ar7pmu6upq7NixA2eddVZ0rPYsWt2FV4Dvz/rV6t69O4CaM2QjR448+QmdsE9d17Fx48ZGm8Xa5y0sLIzb8xIRkbXwM3ZERGQay5Yta/BM1gcffAAA6N27N8aOHYu0tDQUFRXV21YphWPHjgGoaQbbtGmDZ599FqFQKLrNyy+/XK+Bq22cPvvss+hYJBLB/PnzY7Y7++yz0b17dzz22GMIBoP16jxy5EgrZltjzJgxsNlsmD17dr3P59XOb9SoUfB4PJg7dy6qq6vj8rxERGQtPGNHRESmMX36dJSXl+Pqq69Gnz59EAqF8MUXX+D111/HaaedhokTJyInJwdz5szBvffei507d2LMmDFwu93YsWMH/vGPf+CWW27BXXfdhYyMDMyZMwdTpkzBxRdfjJ/+9KfYsWMHXnrppXqfsevXrx/OP/983HvvvTh+/Djy8vLw2muvIRwOx2xns9nw/PPP4/LLL0e/fv0wceJEdOzYEfv27cOyZcvg8Xjw3nvvtWrOPXr0wO9+9zv8/ve/x4UXXoixY8fC4XDgq6++QocOHTBv3jx4PB786U9/wo033ogf/vCHmDBhAtq0aYPdu3dj4cKFGDx4MJ5++ulTzp+IiJKYgStyEhERxfjwww/Vz3/+c9WnTx/lcrmU3W5XPXr0UNOnT1eHDh2K2fbNN99UQ4YMUdnZ2So7O1v16dNHTZ06VW3evDlmuz/+8Y+qW7duyuFwqEGDBqnPPvtMDRs2LOZ2B0optX37djVy5EjlcDhU27Zt1W9/+1u1ePHimNsd1Prmm2/U2LFjVX5+vnI4HKpr165q/PjxaunSpdFtam93cOTIkZjvbezWCi+++KIaOHCgcjgcKjc3Vw0bNkwtXrw4Zptly5apUaNGKa/XqzIzM1X37t3VzTffrNauXduKlImIyIo0pVrx6W0iIiILGD58OABg+fLlhtZBREQUL/yMHRERERERUZJjY0dERERERJTk2NgRERERERElOX7GjoiIiIiIKMnxjB0REREREVGSY2NHRERERESU5NjYERERERERJTk2dkREREREREmOjR0REREREVGSY2NHRERERESU5NjYERERERERJTk2dkREREREREmOjR0REREREVGS+//ztlb2ku2MkAAAAABJRU5ErkJggg==\n" }, "metadata": {} } ] }, { "cell_type": "markdown", "source": [ "Continuous Batching示例:" ], "metadata": { "id": "UlQAuR1OppxG" } }, { "cell_type": "code", "source": [ "# prefill处理优先\n", "engine = Engine(totoal_reqs=8)\n", "anim_viz = AnimatedQueueVisualizer(\n", " data_source_func=engine.run_engine,\n", " interval=800, # 800ms每帧\n", " frames=30 # 30帧\n", ")\n", "\n", "# 在Jupyter中显示动画\n", "anim_viz.show_animation()" ], "metadata": { "id": "Wcg_sOgTpqDn" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "资源抢占情况示例:" ], "metadata": { "id": "Ntw59rbspqO-" } }, { "cell_type": "code", "source": [ "# num_kvcache_blocks=3 kvcache_block_size=10\n", "# 在处理请求总资源超过总3*10t时,将执行队列的队尾请求转移到等待队列\n", "engine = Engine(totoal_reqs=8, num_kvcache_blocks=3, kvcache_block_size=10)\n", "anim_viz = AnimatedQueueVisualizer(\n", " data_source_func=engine.run_engine,\n", " interval=800,\n", " frames=30\n", ")\n", "\n", "# 在Jupyter中显示动画\n", "anim_viz.show_animation()" ], "metadata": { "id": "yG8qUo0Uevt4" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Decode优先的输出" ], "metadata": { "id": "Ido46iYUjOan" } }, { "cell_type": "code", "source": [ "# prefill_first设置为False,即Decode优先\n", "engine = Engine(totoal_reqs=10, prefill_first=False)\n", "anim_viz = AnimatedQueueVisualizer(\n", " data_source_func=engine.run_engine,\n", " interval=800,\n", " frames=30\n", ")\n", "\n", "# 在Jupyter中显示动画\n", "anim_viz.show_animation()" ], "metadata": { "id": "4UwAFNTw18R8" }, "execution_count": null, "outputs": [] } ] }