RFC-0123:CPU 性能信息系统调用 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 用于就 CPU 性能与内核进行通信的接口 |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2021-07-20 |
审核日期(年-月-日) | 2021-08-18 |
摘要
此 RFC 提出了一种机制,使用户空间代理可通过该机制 与内核有关 CPU 性能的信息,两者都旨在更新 并查询其状态。
设计初衷
为了在异构中跨 CPU 有效调度工作 等架构,Zircon 内核调度程序会对 CPU 的相对性能。在撰写本文时, 来表示这些相对表现的量表 静态,由 ZBI 中的数据提供。
对 big.LITTLE 系统执行热 CPU 节流时, 大核心和小核心通常不会按照相同的因素进行扩缩, 它们的相对表现会动态变化。与大多数其他操作系统不同 在 Fuchsia 中,需在用户空间中执行对核心频率的修改,并且 必须跨内核边界通知调度程序相对 CPU 性能。这种通信需要新的系统调用。
设计
效果规模
概念
在考虑提议的系统调用之前,最好先了解一下相关概念 性能规模,这已经存在于内核调度程序中。 性能规模描述的是当下运行时的 CPU 的性能 其当前速度达到依赖于系统的参考性能,其中性能 可以使用任何合适的指标进行衡量,例如 DMIPS。在撰写本文时,但 不一定是将来,参考效果是指 最强大的 CPU 都以最大速率运行,因此最高 CPU 级别为 1.0 效果规模值。通常情况下,供应商会为 每个 CPU 都以标称速度运行,而且我们假定性能会因 与 CPU 频率成线性关系。
例如,在 big.LITTLE 系统中,供应商可能会提供性能数据 这表明大核心在全速运行时, DMIPS 是 以自己的最大速度工作的小型核心。如果参考性能 相当于一个以最大速度运行的大型核心 条件对应的是性能量表 1.0, 那么最大速度的性能范围将为 0.5。减慢大核心的速度 指定 25%,则得到 0.75 的新性能标准 核心速度提高了 25%,将其性能范围更改为 0.375。
更准确地说,如果 fref 是已知频率的参考频率, 效果规模 sref,则频率 fnew 具有 性能规模 snew=sreffnew/fref.一般来说, 实例中每个不同的 CPU 架构都需要参考频率 系统。
通常情况下, 给定系统。例如,通常情况下,同一集群中的 CPU 频率相同,并且每个集群仅支持相对较小的 不同频率的个数。不过,这超出了内核的讨论范围, 跟踪哪些性能量表是有效的。因此,内核信任用户空间。 以提供切合实际的价值,它会使用通过提议 尽其所能。
定点数表示法
为避免使用浮点数,性能规模的表示方法为 由结构体指定的定点数
typedef struct zx_cpu_performance_scale {
uint32_t integral_part;
uint32_t fractional_part; // Increments of 2**-32
} zx_cpu_performance_scale_t;
integral_part
和 fractional_part
描述整数和小数部分,
其中 fractional_part
指定 2-32 的增量。
实点表征和定点表征之间的转换应根据
以下函数:
zx_status_t ToFixedPoint(double real, zx_cpu_performance_scale_t* scale) {
double integer;
double fraction = std::modf(real, &integer);
// Converting from double to fixed point should fail if the input's integer
// part is too large.
if (integer > static_cast<double>(UINT32_MAX)) {
return ZX_ERR_INVALID_ARGS;
}
scale->integral_part = static_cast<uint32_t>(integer);
// Rounding down the fractional part is suggested but should not matter
// much in practice. A difference of 1 in the output is a difference of only
// 2**-32 in the corresponding real value.
scale->fractional_part = static_cast<uint32_t>(std::ldexp(fraction, 32));
return ZX_OK;
}
double FromFixedPoint(zx_cpu_performance_scale_t scale) {
return static_cast<double>(scale.integral_part)
+ std::ldexp(scale.fractional_part, -32);
}
系统调用 1:zx_system_set_performance_info
第一个系统调用允许用户空间代理设置 内核调度程序:
zx_status_t zx_system_set_performance_info(
zx_handle_t resource,
uint32_t topic,
const void* new_info,
size_t info_count
);
其参数为:
resource
:授予此调用权限的资源。必须为ZX_RSRC_SYSTEM_CPU_BASE
,这是专门针对此 否则调用将失败。topic
:此调用引用的效果类型。必须为ZX_CPU_PERF_SCALE
,该值将在提案实施时进行定义。new_info
:有效的zx_cpu_performance_info_t[]
,其元素为 指定者typedef struct zx_cpu_performance_info { uint32_t logical_cpu_number; zx_cpu_performance_scale_t performance_scale; } zx_cpu_performance_info_t;
其中
zx_cpu_performance_t
是定义的 部分。logical_cpu_number
指定结构体描述其信息的 CPU, 采用与内核相同的编号方案每个logical_cpu_number
必须是有效的 CPU 标识符。new_info
的元素 必须按严格递增的logical_cpu_number
进行排序(并且 因此,每个logical_cpu_number
可能仅出现一次)。performance_scale
表示 并且应与 CPU 的新频率相对应,如所述 之前。但是,内核不会验证 基于支持的 CPU 频率的输入;任何正值都可以作为 输入。输入比例
{.integral_part = 0, .fractional_part = 0}
无效,因此 不要与离线核心请求混淆 一种不同的机制 - 预计将来会有其他 API。内核可以在内部使用最接近的值替换有效输入, 调度器可以使用的 Pod例如,在写入时, 支持的性能范围是 1.0。因此,如果
performance_scale
代表大于 1.0 的值,则内核会在内部限制该值 至{.integral_part = 1, .fractional_part = 0}
。如果对
zx_system_set_performance_info
的调用失败,内核会获取 无任何操作,且new_info
无任何影响。如果调用成功,内核调度程序将利用修改后的 从下个开始,
new_info
重新安排操作(通常在调用返回后的某个时间发生)。 对于未引用的 CPU,内核不会修改其性能规模。new_info
。此调用所做的更改将持续到重新启动或直到它们重新启动 被进一步使用此 API 所覆盖。
info_count
:new_info
中的元素数量。必须为正数 超过系统中的 CPU 数量
错误情况
ZX_ERR_BAD_HANDLE
- “
resource
”不是有效的句柄。
ZX_ERR_WRONG_TYPE
resource
不是有效的资源句柄或不是种类ZX_RSRC_KIND_SYSTEM
。
ZX_ERR_INVALID_ARGS
topic
不是ZX_CPU_PERF_SCALE
。new_info
是无效指针。- “
new_info
”不是按照logical_cpu_number
严格递增进行排序。
ZX_ERR_OUT_OF_RANGE
resource
的种类为ZX_RSRC_KIND_SYSTEM
,但不等于ZX_RSRC_SYSTEM_CPU_BASE
。info_count
为0
或超过了 CPU 数量。logical_cpu_number
无效。- 输入
performance_scale
为{.integral_part = 0, .fractional_part = 0}
。
预期用途
zx_system_set_performance_info
应该用于通知内核
随着 CPU 频率的改变,CPU 性能也会随之改变。此 API 支持
因为不同的性能规范
CPU 可以由不同的实体控制。
如果要降低 CPU 频率,建议
在频率更改生效之前调用 zx_system_set_performance_info
错误。这样,内核调度程序就有机会减少
CPU 在容量降低之前(调度程序应
足够快,无需进一步协调;这个期望值
请在实施支持后确认。)
反之,如果要提高 CPU 的频率,建议
频率更改后,系统会调用 zx_system_set_performance_info
并仅在有新容量可用时通知调度程序。
无论是哪种情况,如果 CPU 频率更新失败,调用方都必须更新
根据生成的 CPU 状态启动内核调度程序。调用方应尝试执行
确定发生故障后的 CPU 频率,并使用该频率来
对 zx_system_set_performance_info
的调用。如果无法确定频率
(例如,如果关联的司机直接出现故障),来电者应拨打
对生成的 CPU 速度持悲观(低)猜测。此建议可能会
会不断演变;查看示例
https://fxbug.dev/42165500.
新 API 最终将由待开发的“CPU 管理器”使用 该组件将负责 CPU 的用户空间管理。更确切地说 与 CPU 驱动程序、想要修改 CPU 的代理程序相比, 频率将向 CPU 管理器注册请求,后者将协调 如本方案所述,频率随内核的更新而变化。
CPU 管理器还将接管 CPU 的温控调频 (此提案的激励用例)。
系统调用 2:zx_system_get_performance_info
第二个系统调用可检索所有 CPU 的性能信息:
zx_status_t zx_system_get_performance_info(
zx_handle_t resource,
uint32_t topic,
void* info,
size_t info_count
size_t* output_count
);
其参数为:
resource
:授予此调用权限的资源。必须为ZX_RSRC_SYSTEM_CPU_BASE
。topic
:ZX_CPU_PERF_SCALE
或ZX_CPU_DEFAULT_PERF_SCALE
, 。主题决定内容 写入info
,如下所述。info
:长度等于zx_cpu_performance_info_t[]
系统中的 CPU 数量。如果调用失败,则
info
不会修改。如果调用成功,则返回时,
info
会分别为每个元素包含一个元素 CPU,按logical_cpu_number
递增排序。每个元素的 系统会根据topic
填充performance_scale
:ZX_CPU_PERF_SCALE
:performance_scale
存储内核的当前 指定 CPU 的性能范围。提供的值反映的是 最近一次对zx_system_set_performance_info
的调用,即使下一次调用也不例外 重新安排操作尚未执行。ZX_CPU_DEFAULT_PERF_SCALE
:performance_scale
存储默认值 指定 CPU 启动时内核使用的性能范围。
info_count
:info
数组的长度;必须等于 系统。output_count
:如果调用成功,其中将包含元素数量 已写入info
。如果调用失败,则其值未指定。
错误情况
ZX_ERR_BAD_HANDLE
- “
resource
”不是有效的句柄。
ZX_ERR_WRONG_TYPE
resource
不是有效的资源句柄或不是种类ZX_RSRC_KIND_SYSTEM
。
ZX_ERR_INVALID_ARGS
topic
不是ZX_CPU_PERF_SCALE
或ZX_CPU_DEFAULT_PERF_SCALE
。info
是无效指针。
ZX_ERR_OUT_OF_RANGE
resource
的种类为ZX_RSRC_KIND_SYSTEM
,但不等于ZX_RSRC_SYSTEM_CPU_BASE
。info_count
不等于系统中的 CPU 总数。
预期用途
ZX_CPU_PERF_SCALE
下的行为允许用户空间代理查询
以便进行诊断例如,对于
代理在首次启动时评估系统状态,或将其作为崩溃信号
报告。
ZX_CPU_DEFAULT_PERF_SCALE
下的行为允许代理
确认其配置的性能水平是否与这些
由内核使用。
实现
内核
新系统调用必须实现,由新资源控制
ZX_RSRC_SYSTEM_CPU_BASE
。必须修改内核调度程序以支持动态性能规模, 更新它们以使用
zx_system_set_performance_info
,还会公开其当前正在使用的 默认性能可扩展到zx_system_get_performance_info
。
组件管理器
新协议 CpuResource
必须由
组件管理器,用于提供 ZX_RSRC_SYSTEM_CPU_BASE
资源。这个
遵循之前存在的控制系统调用的资源模式。
性能
新系统调用本身的执行时间微乎其微,因为 它们只需处理少量数据,这些数据与 CPU 数量成正比。
使用 zx_cpu_set_performance_info
会导致调度器分配工作
将工作转移到性能规模提升的核心上
相对于所有性能水平总和,不考虑那些
也会随之降低重新安排流程本身
会给调度器造成大量负载。
重新调度会导致系统性能出现预期的变化。正在测试 这些更改等同于对调度器进行功能正确性测试 问题可在测试中解决。
安全注意事项
两个新系统调用都受新资源句柄的控制
ZX_RSRC_SYSTEM_CPU_BASE
。对于zx_system_set_performance_info
,这项保护措施
解决了对调度器的恶意干扰。对于
zx_system_get_performance_info
,则存在更细微的数据泄露问题;
不应该信任不可信实体,以了解内核性能
体重秤通常提供有关系统支持的
P 状态。
隐私注意事项
此方案对隐私保护没有任何实质性的影响。
测试
- 我们将添加核心测试,以执行基本的成功和失败标准。
- 将添加单元测试,以验证调度器对更新后的 性能规模。他们将验证截止时间线程是否已固定到 CPU,并且该 CPU 的性能规模已由 α 系数修改,那么 将分配给线程的实际时间乘以 1/α。
文档
Zircon 系统调用文档将会更新,以包含新的 API。
缺点、替代方案和未知问题
通用性
考虑了更通用的接口,例如 zx_set_cpu_properties
最终可以处理内核间额外交互的系统调用
和 CPU 等资源最终,我们选择了窄版界面
预计会很少出现此界面的客户,
对建议界面的更改相对较小。对
更通用的界面在这一阶段主要是凭空猜测。
其他调用结构
作为 zx_system_set_performance_info
的“仅集合”操作的替代方法,
考虑了返回之前性能的组合 get/set 操作
缩放。这是出于
确保调用方能够还原性能规模变更
执行失败。
不过,经过进一步的研究发现,如果简单还原更改, 是不够的。这就导致了一套更复杂的故障处理 建议,并引领了更简单的“仅设置”策略 操作。
最后,需要使用 zx_system_get_performance_info
来支持封闭测试。
在这种情况下,直接还原更改是恰当的,并且支持
诊断用例。
备用 CPU 索引
我们考虑过使用其他方案将 CPU 编入索引,例如引用 分配给它们不过,由于内核没有其他需要 与 Zircon 的有限范围限制使用 API, 使用内核的现有逻辑 CPU 编号。这些数字在 客户端可以维护一个静态的 来引用它们或可能访问其配置数据 来自 ZBI。
性能规模的替代方案
我们认为,新的 API 可能会利用“速度因素”调度器将应用于 特定 CPU 的性能扩缩。这样做可以减少 客户需要了解的特定情境信息;而非 了解 CPU 之间的相对性能,只需要知道 CPU 的新频率与其标称频率之间的比率。
我们选择不采用这种方法,因为使用效果规模的预期 是异构系统上的 CPU 温控降频的基本方式, 该 API 的预期客户无法从 速度因素。同时,定义合适的语言模型 并修改调度器以利用新概念。
最大性能规模
此提案最初使用 uint32_t
表示效果范围,
以 [0.0, 1.0] 表示的实值。特别要指出的是,这使
表示最大值 1.0。
虽然 1.0 是 Zircon 调度程序支持的最大性能规模, 于是,我们决定允许表示大于 1.0 来支持未来的用例,例如涡轮模式。此外, 之前的表示法不是定点的,因此会产生值 调度器无法直接使用的名称。
performance_scale
的表示法
performance_scale
原本是 uint64_t
,高 32 位存储
整数部分和较低 32 位存储小数部分。这会
在 zx_cpu_performance_info_t
中的字段之间产生了 32 位的填充,
从而引入了潜在泄露矢量。新的表示形式避免了
错误。
允许 performance_scale
的值
仔细考虑了zx_system_set_performance_info
应允许作为 performance_scale
的输入。“0.0”的值是
已确定太容易与指令混淆,导致 CPU 离线
Zircon 目前不支持
使用其他 API因此,确定了表示 0.0 的值
返回错误。
非常小的值也应特别注意。例如,
{.integral_part = 0, .fractional_part = 1}
表示 2-32,
该值可合理视为 0.0,
相应的核心脱机。虽然可以通过强制执行
允许的最小值,目前任何此类阈值都是任意的,
会使内核与用户空间之间的协定更加复杂。我们觉得
将新 API 视为提示机制是最简单的做法,
如果需要替换输入,内核可以自由替换输入
公开与此类选择相关的内部细节。
未来工作
配置管理
理想情况下,用户空间代理将使用 ZBI 共享完全相同的 CPU 内核调度程序使用的配置数据。尚不清楚 但目前非常实用
此外,必须注意确保内核和用户空间 将默认性能量表与相同的标称频率相关联。
性能规模的下限
原则上,调度器可以确定
系统应根据当前的截止时间线程和 CPU 负载进行维护。动态
这些边界版本将是用户空间代理的重要输入,
尝试利用较低的 CPU 频率来实现能效。额外
zx_system_get_performance_info
选项自然地
公开它们。
CPU 归因
应该建立一些方式来关联线程归因的 CPU 时间 以及调度它所针对的 CPU 的性能。此类关联为 已经与建立可靠的效果指标 在大核心而不是小核心上进行调度,并且相关度 我们开发出与频率调整相关的机械, 提案。
节流代理的保证执行
执行温控降频时降低 CPU 频率可能会导致 CPU 这反过来又会降低节流代理进程 以便及时处理节流代理的执行应 以适当的方式确定优先级。
先验技术和参考资料
将 CPU 频率控制的责任委派给用户空间的情况很常见 操作系统,因此不提供关于此主题的现有技术。