Hw2:理解 LLM 推理生命周期与 AI Service(对应实验二)¶
作业定位¶
Hw2是实验二“LLM 推理生命周期与 AI Service”的配套作业;- 本次作业侧重阅读、分析与书面整理,主线包括:LLM 推理生命周期与性能指标、异步 AI service 的结构演化,以及
wait/query相关语义边界; - 完成本作业后,你应能更顺畅地进入实验二中的代码阅读、性能测量、调试与后续接口设计任务。
作业目标¶
- 从系统实现的角度理解一次 LLM 推理的基本流程,能够围绕“程序读了什么、算了什么、输出了什么”这条主线,说明
tokenization、Prefill、Decode、KV Cache与detokenization分别处在什么位置; - 理解
Model Loading Time、TTFT、TPOT这三个核心服务指标分别衡量什么,能够结合输入长度、输出长度与冷启动过程分析它们为什么会变化; - 理解
Prefill与Decode的资源消耗差异,能够结合实验数据区分compute-bound与memory-bound两类典型瓶颈,并把模型规模、层数、隐藏维度等架构差异映射到性能差异上; - 能够基于当前
llmrun、pipe与进程机制,解释为什么 AI service 会从“用户态直跑”自然演化成“请求队列 + 后台 worker”的异步结构; - 能够从
wait()的语义出发,分析异步 AI service 为什么必须补上请求所有权、状态查询与一次性结果消费语义,并给出自洽的submit/query/wait接口理解。
作业题¶
与实验二的关系
Hw2 是实验二的配套书面作业。你可以将其理解为实验二的预习与整理任务:先阅读下列材料,完成作业题,再在实验课中继续推进对应的代码阅读与实现。
阅读说明
请在完成本次作业前,务必仔细阅读以下配套阅读材料页面:
- Part 1 阅读材料:理解 LLM 推理生命周期
- Part 2 阅读材料:从
llmrun --stdin到“请求队列 + 后台 worker” - Part 3 阅读材料:从
wait()推演所有权、状态查询与一次性结果消费语义
上述文档会帮助你把 Transformer、Prefill/Decode、KV Cache、llmrun、请求队列、后台 worker、wait/query 语义等概念对应到课程代码和后续接口设计中。
Warning
Hw2 的截止时间请以课程公告或 BB 系统页面为准;提交前请确保自己的答案是基于阅读和理解后独立完成的。
开始答题前请先完成环境准备
本次 Hw2 的题面不再展开环境准备细节。开始答题前,请先阅读并完成 Hw2 环境准备与最小检查。
至少请确认以下四件事已经完成:
- 已切换到课程仓库的
AI分支; - 已下载助教提供的
smol.zip/qwen.zip,并正确放到仓库根目录models/下; - 已使用
make qemu-smol或make qemu-qwen完成至少一次最小运行检查,而不是使用普通的make qemu; - 若宿主机需要运行
tools/translate_llm_io.py,已按 Hw2 环境准备与最小检查 中的方法配置好venv。
做 Part 1 前的最小要求
在开始 Part 1 的性能测量前,请至少先完成 Hw2 环境准备与最小检查 中的“模型压缩包下载与放置”“建议先完成一次最小检查”和“宿主机侧 tokenizer 依赖”三节内容。
Part1 题目(30 分)¶
题目:从系统视角分析 LLM 推理的性能指标与资源压力点
在现代云计算与AI基础设施中,大语言模型(LLM)已被广泛封装为云端API或微服务。对于系统工程师而言,保障LLM推理服务的高效性和稳定性是核心任务。 当我们向用户提供LLM服务时,通常会受到严格的服务级别目标(SLO, Service Level Objectives)限制。用户的体验不仅取决于模型有多“聪明”,更取决于系统有多“快”。此外,在云原生环境中,为了应对突发的流量洪峰,系统需要动态扩容(水平扩展),这就带来了“冷启动(Cold Start)”问题。
为了评估和优化这些系统表现,我们需要关注以下几个核心的服务指标(Serving Metrics):
-
模型加载时间 (Model Loading Time):将模型权重(Weights)从持久化存储(如硬盘)加载到内存(DRAM)的总耗时。这是决定模型实例冷启动开销的核心部分。
-
首 Token 延迟 (Time To First Token, TTFT):从系统接收到用户的请求,到模型生成并返回第一个 Token 所经历的时间。这主要包含了处理用户输入(Prompt)的 Prefill 阶段的开销,直接决定了用户的“等待响应”体验。
-
每个输出 Token 的时间 (Time Per Output Token, TPOT):在生成第一个 Token 之后,后续每个 Token 生成的平均耗时。这对应了模型的 Decode 阶段,反映了模型持续输出内容的速度。
任务A:基础性能剖析¶
请运行 SmolLM2-135M 模型进行推理,完成以下三个步骤:
-
说明测量机制: 阅读第一部分的文档,结合仓库代码中的提示,在报告中明确指出你的测量起点和终点。例如:你是如何设置代码来单独提取
TTFT和TPOT的? -
开展变长负载测试: 分别改变输入 prompt 长度与输出长度,测量上述三个核心指标的变化。建议至少设置三组不同长度的测试用例(例如:短输入输出 8 tokens,中等长度 16 tokens,长序列 32 tokens)。要求用表格或折线图的形式清晰整理数据。
-
定位系统瓶颈: 结合
Prefill、Decode、KV Cache与冷启动等底层机制,根据你的实验数据回答:-
哪些指标主要受输入长度影响?哪些指标主要受输出长度影响?
-
这些耗时变化中,哪些阶段反映的是系统的计算压力,哪些变化更接近访存(内存带宽)压力?请给出你的判断依据。
-
任务B:跨架构规模的对比¶
在完成任务A的基础上,引入参数规模更大的 Qwen3.5-0.8B 模型进行性能测试,完成以下两个步骤:
-
跨模型基准对比:在相同的硬件环境下,分别获取
Qwen3.5-0.8B短/中/长序列的数据,并横向比较它和SmolLM2-135M在Model Loading Time、TTFT、TPOT上的差异。 -
架构差异与性能映射 :请查阅这两个模型的相关资料或代码配置,对比它们的关键维度差异(如:模型整体参数量、Transformer 层数、隐藏层维度 Hidden Size 等)。
- 结合这些具体差异,解释为什么它们会以不同程度影响模型加载时间、TTFT 和 TPOT?
- 提示:可以从模型权重对 I/O 的负担、矩阵乘法维度对算力的需求等角度展开说明。
实验环境提示
本次实验在单核CPU环境下运行,由于单核算力与内存带宽受限,大模型的推理耗时可能会较长,这是正常的现象。请耐心等待测量结果,并确保在测量过程中没有其他资源密集型任务干扰。
Part 2 题目(35 分)¶
题目:为什么 AI service 会从“用户态直跑”演化成“请求队列 + 后台 worker”
请结合 Part 2 阅读材料,假设后续实验会把当前这条用户态推理路径进一步封装成:
int ai_submit(const uint32 *tokens, int token_count, int predict_count);
int ai_wait(int reqid, char *out, int out_cap);
int ai_query(int reqid, struct ai_status *st);
作答说明
这是一道设计分析题。你给出的结构不要求与代码完全一致,但必须满足下面三点:
- 能从当前
llmrun、pipe和进程机制自然推导出来 - 请求槽、队列、worker、
wait/query之间的职责划分清楚 - 阻塞点、唤醒条件和结果取回语义前后一致
作答时以抓住主线为准,不要求把阅读材料中的所有细节全部展开。
请完成下面三个小任务。
任务 A:画异步服务结构图¶
画一张 producer-consumer 结构图,至少包含:
- 调用进程
ai_submit- 请求缓冲区
- 后台
ai_daemon或 worker ai_wait
要求:
- 明确谁是 producer,谁是 consumer
- 明确哪个对象承担“排队”作用
- 明确结果是在哪里等待、在哪里取回
- 你可以把“请求槽 + 循环队列”合并画成一个总框,但图中必须标明:谁负责存放请求信息,谁负责排队
- 图可以用手绘、PPT 框图或 ASCII 框图表示
任务 B:指出一类典型阻塞点¶
结合 sleep() / wakeup() 和 pipe 的阅读,任选 一类 典型阻塞点展开说明,并分别回答:
- 是谁在阻塞
- 它在等什么条件
- 谁会负责唤醒它
可以从下面这些方向中任选其一:
- 队列空,worker 无事可做
- 槽位满,新的提交无法进入
- 请求未完成,调用者在
wait中等待
如果你愿意,也可以额外用 1-2 句话再点出另一类阻塞点,但不作为必做要求。
任务 C:解释为什么 AI 更适合异步¶
用不超过 200 字,或 2-3 条要点回答:
- 为什么“把 AI 推理直接塞进一次同步调用”不是长期服务的好结构
- 为什么“submit + 后台 worker + wait/query”更适合 AI 这类负载
- 回答中至少提到下面关键词中的 一个:
- 复用
- 解耦
- 排队
- 背压
- 长驻
Part 3 题目(35 分)¶
题目:为什么异步 AI service 必须补上所有权、状态查询和一次性结果消费语义
请结合 Part 3 阅读材料,完成下面三个小任务。
作答说明
这是一道语义设计题。只要你的字段选择、状态划分和 wait/query 语义是自洽的,就可以视为合理答案;不要求逐字一致。
作答时以“最小可行语义”为准,不要求穷举所有边界情况。
任务 A:设计最小状态信息¶
请分别给出你认为最小可行的:
ai_request元数据字段ai_status对外可见字段
要求:
- 不要求写成完整 C 结构体
- 只需按“字段名 + 一句话用途”的形式列出
ai_request建议写3-4个字段,ai_status建议写2-3个字段- 两组字段合计建议控制在
6个以内;如果你认为需要更多字段,请说明其必要性 - 字段名可以直接沿用阅读材料中的示意,也可以自行命名
任务 B:用 wait() 类比说明语义¶
结合 kernel/core/proc.c 中 wait() 的行为,用不超过 200 字说明:
- 为什么一个 AI 请求必须记录“属于谁”
- 为什么“知道
reqid”不等于“有权限wait/query” - 为什么一个请求完成后,结果被成功取走一次就应该回收,而不是永久保留
任务 C:填写语义表¶
请补全下面场景的期望行为与理由。
| 场景 | 期望行为 | 理由 |
|---|---|---|
提交者在请求尚未完成时调用 ai_query(reqid, st) |
||
提交者在请求完成后第一次调用 ai_wait(reqid, out, cap) |
||
同一个提交者第二次对同一 reqid 调用 ai_wait(...) |
||
其他进程或子进程拿到这个 reqid 后调用 ai_query(...) |