news 2026/10/11 3:58:56

Exec 跨度与复测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Exec 跨度与复测

承接上一篇《性能三问:从一张 docx 对照表到 100C+100R》。又追了三条:
①数据浮动这么大,原因何在?②你取的数据有意义吗?③C 版本的 exec 是不是也这样?

先把三个答案摆在前面

Q1:C 版本的 exec 也是这样吗?——是

(先补一句背景:「同门」= 两臂走完全相同的内核路径与同一份二进制协议,唯一变量是用户态库由 C 还是 Rust 写;「门」= gdev 的两种部署形态——内核门(经过内核模块 gdev.ko)与用户门(纯用户态驱动)。本篇两臂都走内核门。详见上一篇。)

臂发数中位min–max跨度
C(内核门)1000.4050.124–1.0838.7×
Rust(内核门)1000.3170.117–1.17910.1×

同一个 GPU、同一扇门、同样 40µs 的活,两个语言版本的 Exec 服从同一条又宽又稳的分布(KS 检验 D=0.160 < 临界 0.192,无法区分)。所以「浮动」不是哪一版的毛病——它不由语言负责。

Q2:为什么浮动这么大?——「等完成」的唤醒路径里,藏着一个 0~1ms 的随机惩罚

Exec 那一段计的是「提交内核 + 等它算完」。插针版把它拆开(36 发带分项计时):

分量实测稳不稳
提交(cuLaunchGrid)C 4–7µs / Rust 10–13µs稳
GPU 真算(512×512 矩阵加)~40µs硬件确定性
等完成(cuCtxSynchronize,内核门)0.3–0.93ms全部方差在这

内核门的「等完成」是睡在内核里、由完成中断叫醒。唤醒函数里有一处竞争回退(gdev_sched_wakeup,gdev_drv.c:297-304):如果完成通知到得太早——等待方还没真正睡稳——通知方就自己睡到下一个时钟滴答再补叫。这台机器CONFIG_HZ=1000,一个滴答 = 1ms——这笔罚的上限因此是 1ms。

0.13ms 的地板(提交+执行+无竞争唤醒)+ 等待路径的随机延迟 = 0.13~1.2ms 的观测分布。

400 发(本轮 200 + 档案 200)的定量检验给出更细的图景(下图):约四成发走无竞争快车道(≤0.3ms),其余构成慢带——慢带不是均匀铺开的,而是右偏单峰(众数≈0.3ms,长尾到 1ms):主体是普通的调度唤醒延迟(中断到了、任务醒了,但 vCPU 排上真实 CPU 核要排队——天然右偏),滴答回退贡献 ≤1ms 的长尾成分。「慢带=单一均匀罚」的简化说法已被 KS 检验拒绝(D=0.226 ≫ 临界 0.086)——检验过程见「环境这一环」一节的证据分级表。

对照组一锤定音:用户态门的「等完成」是轮询自己 mmap 的寄存器,不睡内核、不进调度器——同负载 10 发只动 6µs(CV≈2%),稳如磐石。哪个环节在抖,一对照就现形。

三次独立采样(各 100 对)的 R/C =0.90 / 1.13 / 0.78,方向翻了两次、全部区间交叠、全部不显著。
三次都指向同一句话:同门之下,C 和 Rust 之间不存在值得立案的性能差。

代码现场:这段代码为什么这么写

根因代码原样贴出(内核模块mod/gdev/gdev_drv.c:292-306,C/Rust 两臂共享):

/* 等待方:睡进内核,不被信号打扰 */voidgdev_sched_sleep(void){set_current_state(TASK_UNINTERRUPTIBLE);schedule();}/* 通知方:叫醒等待者 */intgdev_sched_wakeup(void*task){if(!wake_up_process(task)){/* 返回 0 = 没叫醒:对方还没睡下 */schedule_timeout_interruptible(1);/* ← 波动源头:睡到下一个滴答,再补叫一次 */if(!wake_up_process(task))return-EINVAL;}return0;}

完整链条(逐行核实过):用户进程发起同步等待 → 入队后按上面的模式睡下;GPU 算完触发中断 →通知处理器(gdev_drv.c:63)叫醒 gdev 的调度内核线程(:88)→ 调度器选出已完成的上下文、将其出队,再gdev_sched_wakeup(se->task)叫醒用户进程(common/gdev_sched.c:297-301)——竞争回退就发生在最后这一步。失败分支的报错文案写的就是
「Perhaps context %d is already up」(:303)。

在防什么:唤醒丢失(lost wakeup)

经典并发陷阱。wake_up_process()只能叫醒已经睡着的任务;如果通知到得太早——等待方还没执行到set_current_state那行、还在正常跑——这次唤醒就是无效的(返回 0),而通知是一次性的、不会排队。没有这段 fallback,等待方随后睡下就永远没人叫:每次撞上这个窗口= 死锁。所以修法是「等一个滴答(这时对方必然已走到睡点),再叫一次」——用有界的延迟换不丢唤醒,教科书级的正确性权衡。在 2012 年前后的裸机研究原型里(竞争窗口纳秒级、命中率极低、HZ=1000 下最多 1ms),这是个完全合理的选择。

环境这一环:哪些已证,哪些是推断

「赖虚拟机」恰恰是整条因果链里唯一没有直接测量的一环——全程只有虚拟机这一个环境,
没有裸机基线。把每一环按证据强度排开:

环节等级依据
抖动全部来自「等完成」路径已证插针分解(提交/GPU 执行均稳)
慢带呈多峰离散结构(0.2-0.4 隆起、0.72-0.76 与 0.92-0.98 窄簇),非均匀非简单右偏已证400 发 0.02ms 细桶直方图;「单一均匀罚」被 KS 检验拒绝(D=0.226 ≫ 0.086)
虚拟化放大命中频率推断机制成立(见下),缺裸机对照

机制(讲得通,未测):测试机是宿主机上的一台虚拟机(GTX 580 PCI 直通),GPU 完成中断要宿主机转发注入,虚拟机的 CPU 是宿主机上的线程、与同宿主其他虚拟机抢物理核。关键不是「通知来得早」,而是睡觉的一方被耽误——提交之后、走到睡觉代码之前,vCPU 一旦被宿主机调度走几十微秒,而完成链(另一个核)照常推进,「去叫时人还没睡下」即命中;虚拟机让这种
抢占频繁发生。

旁证与责任划分:同一台虚拟机里,走用户门(不睡内核、轮询等待)的对照组纹丝不动(CV≈2%)——虚拟机本身不给计时加噪,加噪的是这段对调度抖动脆弱的等待代码。所以最准确的说法是:根在代码的等待设计(对任何调度抖动都脆弱,裸机上同样会命中、或许罕见),虚拟机是疑似放大器。

验证(按代价排序,阶段一已完成):

  • 阶段一(已完成):用 400 发既有数据检验模型的定量预测——「均匀罚」被拒绝,
    模型细化为两成分;顺带发现两臂慢带命中率差 12 个百分点(上表新线索);
  • 阶段二(未执行):给gdev_sched_wakeup回退分支挂 ftrace 计数,分臂
    统计命中次数——一次实验同时裁两件事:命中率从推断变实测、两臂差异定论(不改源码)。
  • 阶段三(未执行):宿主机给测试虚拟机绑独占物理核,看慢带占比是否随 vCPU 抢占消失而降

另两条已证的机制事实:

  • 代价是随机的:schedule_timeout_interruptible(1)睡到的是下一个滴答边界,落在1ms 周期内的哪个相位纯看运气——(0,1ms] 均匀分布,不是固定 1ms;
  • 另一方面:TASK_UNINTERRUPTIBLE让等待不可被信号打断——GPU 楔死时,等待方kill -9都杀不掉(模块内 5 处睡眠点全是同一模式)。防丢唤醒的坚韧,和故障处置的困难 (每次楔死只能整机复位),是同一个设计决定的正反面。

意外收获:楔死的节律

复测途中楔死 38 发,全部留证。规律清晰得意外:每个「复位+装驱动」的新鲜周期,恰好能跑~19 发绿,然后楔死簇发(2~7 连楔);暂停 3 分钟/5 分钟/40 分钟都不能自愈,只有整机复位恢复。楔死瞬间的内核日志全是同句:nouveau PFIFO 写缺页(显存页不存在)——资源耗尽形态,已单独整理。

复测怎么跑的(一段工程花絮)

每个周期 = 整机复位 → 重装两个内核模块 → 建设备节点 → 从断点号续跑;runner 自带两臂计数、楔死穿透(单楔只记录不中止)、连续 3 楔自保停机。

数字

采样C medR medR/Cp(置换)
档案同门轮0.4210.3790.900.17
本轮预跑(18v19)0.2820.3191.130.87
本轮终版(100v100)0.4050.3170.780.094
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/11 3:55:13

全国地级市二手房房价数据(2011-2025):Excel与Shp双格式实战指南

2011到2025年&#xff0c;整整15年&#xff0c;覆盖全国两百多个地级市的二手房房价数据&#xff0c;还同时提供Excel和Shp两种格式——第一次凑齐这样一份数据的时候&#xff0c;我第一反应不是兴奋&#xff0c;反而是警惕。做数据分析的人都知道&#xff0c;越“完整”的数据…

作者头像 李华
网站建设 2026/10/11 3:52:36

Python爬虫实战:采集财富中国500强榜单数据

1. 项目概述1.1 为什么要采集财富中国500强数据财富中国500强榜单每年发布一次&#xff0c;涵盖了国内规模最大、盈利能力最强的头部企业。这份榜单不仅是投资研究、行业分析的高频数据源&#xff0c;也是很多商业课程、市场调研报告里绕不开的核心素材。我接下这个案例的时候&…

作者头像 李华
网站建设 2026/10/11 3:52:16

嵌入式面试技术全对没用?30K要的是解决问题的能力

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/11 3:51:04

BeagleY-AI 嵌入式 AI 实战:从开箱到 Python 推理与 GPIO 控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/11 3:48:05

H3C ACL配置:仅放行指定IP访问445端口的安全加固实践

刚接手一个网络加固需求的时候&#xff0c;总有那么几个看似简单、动手就翻车的任务。“拒绝所有IP访问445端口&#xff0c;但允许特定IP访问”就是典型代表。445端口在Windows环境里承担着SMB文件共享的职责&#xff0c;也经常被各种利用445端口的恶意程序盯上&#xff0c;很多…

作者头像 李华