交作业,关于 Intel B70 PRO 的压力测试。
-
以下是新内容,前天的是处理的2024年全年的图片,有240多张,昨天处理了2026年的,只有 90张。 为了更进一步的压榨这卡的能力,于是我把原代码中的6步并发,改为16个并发! 我看是否它还可以抗得住,代码如下:
import base64 import os import glob import asyncio import aiohttp from io import BytesIO from PIL import Image API_URL = "http://localhost:8091/v1/chat/completions" IMAGE_DIR = "./cb*.png" OUTPUT_CSV = "./cb_data_full_fixed.csv" # B70 32G 显存并发数 CONCURRENCY = 16 def encode_image_from_bytes(image_bytes): return base64.b64encode(image_bytes).decode('utf-8') def slice_long_image(image_path, slice_height=1500): img = Image.open(image_path) width, height = img.size slices = [] for i in range(0, height, slice_height): box = (0, i, width, min(i + slice_height, height)) slice_img = img.crop(box) buffered = BytesIO() slice_img.save(buffered, format="PNG") slices.append(buffered.getvalue()) return slices async def fetch_and_process_slice(session, date_str, slice_base64, slice_index, file_lock): payload = { "model": "/model", "messages": [ { "role": "system", "content": "你是一个无情的数据提取机器。直接输出CSV,不要任何多余文字。" }, { "role": "user", "content": [ { "type": "text", "text": "提取图片表格中所有可转债数据。请直接输出CSV格式。每行字段为:转债代码,转债名称,价格,涨幅,正股,正股价,溢价率。注意:不要包含表头,不要使用Markdown代码块(如 ```csv)。如果图片中没有完整数据行,请不要编造。" }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{slice_base64}" } } ] } ], "max_tokens": 4096, "temperature": 0.0 } try: async with session.post(API_URL, json=payload) as response: if response.status != 200: print(f"⚠️ {date_str} (切片 {slice_index}) 请求失败") return res_json = await response.json() result = res_json['choices'][0]['message']['content'].strip() async with file_lock: with open(OUTPUT_CSV, "a", encoding="utf-8-sig") as f: for line in result.split('\n'): # 过滤掉可能的空行和重复生成的表头 if line.strip() and "," in line and "转债代码" not in line: f.write(f"{date_str},{line.strip()}\n") except Exception as e: print(f"❌ 处理 {date_str} (切片 {slice_index}) 发生异常: {e}") async def main(): image_list = sorted(glob.glob(IMAGE_DIR)) if not image_list: print(f"❌ 错误:没有找到符合 {IMAGE_DIR} 的图片!") return print(f"🔥 找到 {len(image_list)} 张超长图,准备进行切片并高并发推断...") if not os.path.exists(OUTPUT_CSV): with open(OUTPUT_CSV, "w", encoding="utf-8-sig") as f: f.write("日期,转债代码,转债名称,价格,涨幅,正股,正股价,溢价率\n") semaphore = asyncio.Semaphore(CONCURRENCY) file_lock = asyncio.Lock() async def sem_task(session, date_str, slice_bytes, index): async with semaphore: slice_b64 = encode_image_from_bytes(slice_bytes) await fetch_and_process_slice(session, date_str, slice_b64, index, file_lock) timeout = aiohttp.ClientTimeout(total=None) async with aiohttp.ClientSession(timeout=timeout) as session: tasks = [] for img_path in image_list: date_str = os.path.basename(img_path).replace("cb", "").replace(".jpg", "").replace(".png", "") # 对超长图进行切片 slices_bytes = slice_long_image(img_path) print(f"✂️ {date_str} 被切分为 {len(slices_bytes)} 块,加入队列...") for index, slice_bytes in enumerate(slices_bytes): tasks.append(sem_task(session, date_str, slice_bytes, index)) # 将所有切片任务并发执行 await asyncio.gather(*tasks) print("🎉 全部长图切片处理完成!去检查数据量吧!") if __name__ == "__main__": asyncio.run(main())直接上图

这是结果,图片太少,不知道啥时候完成的,应该是昨天晚上半夜。16并发时的显卡压力, 频率到了2583, 显卡瓦数到了228.还没有到顶,这卡到顶300,官方说是290,但我的确用到过瞬时300. 显存占用率 96.91% 。

这是在运行时的模型吞吐量。 大概230-280 tokens/s。 这超出了在开始测试时的180tokens/s 。 有懂的可以告诉我为啥... 同样是 Avg Generation troughput 为啥在直接和它对话时在180/s 而现在却到了280多? 是模型预热好了? 费解。

不管咋说,26年的90张处理完毕,下一步计划是把并发增加到... 26? 再试试25年的数据,25年有240多张图片。 尽请期待测试结果。
-
T terry 固定了该主题
-
@sirwang 你问到为什么并发从16加到26后token吞吐量会上下剧烈跳动(299降到十几个),这个现象的本质是KV Cache内存争抢。
B70 32G显存跑Qwen3.6-27B时,每个并发请求都要占用一段KV Cache空间。Q4_K_M的27B模型,单个请求的KV Cache大约占 0.5-1GB(取决于context长度)。16并发时总KV Cache约8-16GB,显存还有余量;但到26并发时,KV Cache总量逼近甚至超过可用显存,vLLM/llama.cpp的调度器就会频繁做cache eviction和recomputation——排到你的请求就快(cache命中),排不到就要等别人释放cache,token就只能慢慢出。
你朋友说16-20并发最合适,道理就在这个临界点:低于16时显存充裕但浪费算力,高于20时cache thrashing的代价超过并发收益。实际调参建议:
- 观察显存占用:跑的时候watch nvidia-smi,看memory-usage%在26并发时是否接近100%且持续抖动。如果在95%以上剧烈波动,就是cache thrashing。
- 短context可以加并发:如果每个请求的输入/输出长度很短(几百token),单个请求的KV Cache占用小,可以尝试24-30并发。
- 调max-num-seqs下限:设 --max-num-seqs 18,让调度器主动限制并发量,比让它在26并发时被动thrashing要快得多。
- 启用vLLM的prefix caching(如果用的vLLM):加 --enable-prefix-caching,多个相似请求共享KV Cache前缀,显著降低cache压力。
简单说:你的硬件能力曲线不是线性的——16并发跑N tokens/秒,26并发可能反而因为thrashing降到只有1.2N。找自己硬件的甜蜜点才是关键。
-
@applejuice 这不是期待intel的会有更多深挖的东西嘛,哇哈哈哈。我还在深挖。
-
@applejuice 这不是期待intel的会有更多深挖的东西嘛,哇哈哈哈。我还在深挖。
@sirwang
大哥来踩坑
我什么都不重要,最重要性比价 高 -
@mark 永远不要低估后起之秀。未来的不确定性不正是我们想验证和追求的吗?
-
系统 取消固定了该主题

