ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

QEMU virtio-balloon 客户机内存统计:guest-stats 轮询机制与 QMP 查询实战指南

QEMU virtio-balloon 客户机内存统计:guest-stats 轮询机制与 QMP 查询实战指南 QEMU virtio-balloon 客户机内存统计guest-stats 轮询机制与 QMP 查询实战指南【免费下载链接】qemuOfficial QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website.项目地址: https://gitcode.com/gh_mirrors/qe/qemuvirtio-balloon 是 QEMU 中最常用的客户机内存动态管理设备除了回收与返还内存页之外它还支持把客户机内核的内存统计信息上报给宿主机。QEMU 将这些统计通过 QOMQEMU Object Model设备属性以轮询方式暴露给外部工具本文基于 docs/interop/virtio-balloon-stats.rst 为主线结合 hw/virtio/virtio-balloon.c 与virtio_balloon.h内核协议头完整讲解统计轮询的开启/关闭、guest-stats属性结构与全部统计项语义、底层 virtqueue 数据流以及一套可直接复制到-qmp终端或qom-set/qom-get调用中的实战示例。一、背景balloon 设备为何要上报内存统计virtio-balloon 设备向客户机暴露两个核心能力一是通过“膨胀/收缩”调节客户机可用内存二是通过统计通道把客户机内核的内存使用情况反馈给宿主机。后者使宿主机侧的监控、调度与内存热插拔决策能够感知客户机内部的真实压力例如 swap 换入换出、缺页、可用内存等而不是只依赖宿主机自己的视角。在 QEMU 中统计功能的载体是 QOM 设备属性通过 QMP 的qom-set/qom-get访问无需在客户机内安装额外 agent——只要客户机内核加载了 virtio_balloon 驱动并支持 stats 功能即可。二、开启轮询guest-stats-polling-interval 属性按文档说明查询统计之前必须先用qom-set向guest-stats-polling-interval属性写入一个以秒为单位的间隔值该属性的合法取值语义如下取值行为 0开启轮询设备按指定间隔周期性地向客户机驱动请求统计若轮询已开启则把间隔修改为新值0关闭轮询此前轮询得到的统计仍然有效可以继续查询从源码看该属性的 get/set 回调是balloon_stats_get_poll_interval与balloon_stats_set_poll_interval注册于 hw/virtio/virtio-balloon.c 第 1042-1045 行object_property_add(obj, guest-stats-polling-interval, int, balloon_stats_get_poll_interval, balloon_stats_set_poll_interval, NULL, NULL);balloon_stats_set_poll_interval第 297-340 行对输入做了严格校验这解释了属性的边界行为value 0报错timer value must be greater than zero负值被拒绝value UINT32_MAX报错timer value is too bigvalue 0调用balloon_stats_destroy_timer销毁定时器并关闭轮询但不清空已收集的统计这正是“关闭轮询后旧统计仍可查询”的实现基础value与当前间隔相同直接返回不做任何操作轮询已开启时仅更新stats_poll_interval并调用balloon_stats_change_timer重排定时器轮询未开启时新建一个基于QEMU_CLOCK_VIRTUAL的毫秒级定时器timer_new_ms回调为balloon_stats_poll_cb。三、查询统计guest-stats 属性的返回结构轮询开启后用qom-get查询guest-stats属性即可拿到统计。该属性只读回调为balloon_stats_get_all第 256-287 行返回一个包含两个键的字典stats所有可用统计项的键值对字典。若客户机不支持某一项或该项无法取到其值固定为-1last-update最近一次统计更新的宿主时间戳秒Unix 时间。该时间由宿主机在收到统计时用g_get_real_time() / G_USEC_PER_SEC生成因此恶意/异常客户机无法伪造其值若客户机从未更新过统计值为0。四、全部统计项一览文档列出的统计项对应内核协议头 include/standard-headers/linux/virtio_balloon.h 中定义的 tag 编号VIRTIO_BALLOON_S_*0~15。QEMU 侧的名称映射表balloon_stat_names位于 hw/virtio/virtio-balloon.c 第 177-197 行其中文档明确列出的 10 项为属性键内核 tag含义stat-swap-inVIRTIO_BALLOON_S_SWAP_IN(0)swap 换入的内存总量stat-swap-outVIRTIO_BALLOON_S_SWAP_OUT(1)swap 换出的内存总量stat-major-faultsVIRTIO_BALLOON_S_MAJFLT(2)主缺页major faults次数stat-minor-faultsVIRTIO_BALLOON_S_MINFLT(3)次缺页minor faults次数stat-free-memoryVIRTIO_BALLOON_S_MEMFREE(4)空闲内存总量字节stat-total-memoryVIRTIO_BALLOON_S_MEMTOT(5)内存总量字节stat-available-memoryVIRTIO_BALLOON_S_AVAIL(6)可用内存与/proc/meminfo语义一致字节stat-disk-cachesVIRTIO_BALLOON_S_CACHES(7)磁盘缓存大小字节stat-htlb-pgallocVIRTIO_BALLOON_S_HTLB_PGALLOC(8)HugeTLB 页分配次数stat-htlb-pgfailVIRTIO_BALLOON_S_HTLB_PGFAIL(9)HugeTLB 页分配失败次数需要说明的是当前 QEMU 的balloon_stat_names表实际映射了VIRTIO_BALLOON_S_NR16见头文件第 80 行全部 tag除上述 10 项外还包括stat-oom-kills、stat-alloc-stalls、stat-async-scans、stat-direct-scans、stat-async-reclaims、stat-direct-reclaims对应 tag 10~15。G_STATIC_ASSERT(G_N_ELEMENTS(balloon_stat_names) VIRTIO_BALLOON_S_NR)保证了表长度与协议一致。因此文档所说“目前支持以下统计项”指的是 Linux 客户机驱动普遍上报的核心子集而 QEMU 侧会为所有 16 个 tag 都准备一个输出键。无论客户机上报多少个统计QEMU 输出时都会补齐全部键——这正是“缺失项值为-1”的来源reset_stats()第 208-212 行在初始化与每次更新前把dev-stats[]全部置为-1随后只有客户机实际上报的 tag 才会被覆盖为真实值。五、底层原理统计 virtqueue 与轮询定时器的数据流统计通道在 virtio 层由一个独立的统计 virtqueuesvq承载且依赖特性位VIRTIO_BALLOON_F_STATS_VQ。balloon_stats_supported()第 214-218 行通过virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ)判断客户机是否支持统计该特性在virtio_balloon_get_features第 792 行中被加入设备特性集合。QEMU 侧驱动名称为virtio-balloonPCI 形态与 s390x CCW 形态分别在 hw/virtio/virtio-balloon-pci.c 与 hw/s390x/virtio-ccw-balloon.c 中封装。完整流程如下客户机驱动先投递一个空请求 buffer 到统计 virtqueue。virtio_balloon_receive_stats第 462-499 行从队列中弹出该请求并暂存为s-stats_vq_elem同时调用reset_stats清空旧值。轮询定时器到期后balloon_stats_poll_cb第 239-254 行把暂存的请求 push 回 virtqueue 并virtio_notify通知客户机相当于“现在请上报统计”。客户机内核应答把一组struct virtio_balloon_stat { uint16_t tag; uint64_t val; }大小端由virtio_tswap16/64转换写回队列。virtio_balloon_receive_stats逐个解析把tag VIRTIO_BALLOON_S_NR的项写入s-stats[tag]最后更新s-stats_last_update。外部通过qom-get guest-stats时balloon_stats_get_all按balloon_stat_names顺序遍历 16 个键输出并附带last-update。值得注意的是balloon_stats_poll_cb中的两个分支若s-stats_vq_elem NULL客户机还没投递请求 buffer或客户机不支持统计则直接重新调度下一次轮询balloon_stats_change_timer只有拿到待应答请求且支持统计时才会触发通知。文档中“轮询定时器仅在客户机响应统计请求后才重新武装”的表述正是源于此若一个异常客户机从不响应请求定时器永远不会被重新武装效果等同于关闭轮询。另外virtio_balloon_reset_enter第 1015-1028 行在设备复位时调用reset_stats并把stats_last_update清零但RESET_TYPE_WAKEUP从挂起唤醒除外——这保证挂起唤醒后统计不会被无谓清空。六、QMP 实战示例可直接执行以文档原始示例为基础QEMU 以-device virtio-balloon启动时匿名设备生成 QOM 路径/machine/peripheral-anon/device[1]。若启动时显式指定-device virtio-balloon,idballoon路径则为/machine/peripheral/balloon这也是 tests/qtest/virtio-balloon-test.c 中使用的路径。下面示例使用匿名路径1) 开启轮询间隔 2 秒{ execute: qom-set, arguments: { path: /machine/peripheral-anon/device[1], property: guest-stats-polling-interval, value: 2 } } { return: {} }2) 把轮询间隔改为 10 秒轮询已在运行仅更新间隔{ execute: qom-set, arguments: { path: /machine/peripheral-anon/device[1], property: guest-stats-polling-interval, value: 10 } } { return: {} }3) 获取统计{ execute: qom-get, arguments: { path: /machine/peripheral-anon/device[1], property: guest-stats } } { return: { stats: { stat-swap-out: 0, stat-free-memory: 844943360, stat-minor-faults: 219028, stat-major-faults: 235, stat-total-memory: 1044406272, stat-swap-in: 0 }, last-update: 1358529861 } }注意示例返回值中只出现了客户机实际上报的 6 个键按源码行为未上报项在内部仍为-1实际输出时balloon_stats_get_all会为全部 16 个键生成条目。4) 关闭轮询{ execute: qom-set, arguments: { path: /machine/peripheral-anon/device[1], property: guest-stats-polling-interval, value: 0 } } { return: {} }需要提醒原文档此处的最后一个示例把属性名误写为stats-polling-interval正确属性名应为guest-stats-polling-interval源码注册名见上文上例已按正确写法给出。七、必须注意的行为细节综合文档与源码使用中有以下几点容易踩坑关闭轮询不清空旧数据此前轮询到的统计在关闭后依然有效、可查询-1的两种含义客户机永久不支持某项值恒为-1vs. 客户机本次更新暂时缺项reset_stats置为-1。后者只需等待下一次更新即可不必惊慌客户机无 stats 支持时也可以开启轮询即使客户机内核没加载 balloon 驱动或不支持 stats 特性qom-set依旧成功此时查询guest-statslast-update为0定时器不再武装等同于关闭轮询如果有缺陷的客户机从不响应统计请求定时器不会重新武装效果与关闭轮询一致负值与超大值都会被拒绝set_poll_interval对value 0与value UINT32_MAX分别报错写入时注意取值范围。八、仓库中的测试佐证QEMU 自带的 qtest 用例直接验证了guest-stats属性位于 tests/qtest/virtio-balloon-test.c它用-device virtio-balloon,idballoon -nodefaults启动随后发起qom-get路径/machine/peripheral/balloon并断言返回的stats字典大小等于VIRTIO_BALLOON_S_NR16即所有已知 tag 都会以键的形式出现。功能测试 tests/functional/x86_64/test_virtio_balloon.py 中也涉及对guest-stats的轮询与断言。这些用例为本文所述属性名、返回结构与键集合提供了可执行验证读者可基于当前仓库直接运行相关 qtest 复现。九、小结virtio-balloon 的统计通道把客户机内核的内存视图通过一条专用 virtqueue 与一个宿主定时器“翻译”成 QOM 属性外部监控系统只需三步即可接入qom-set guest-stats-polling-interval开启轮询 → 等待一个间隔 →qom-get guest-stats读取stats与last-update。理解-1的语义、定时器只在客户机应答后重武装这两个细节能帮助你在真实环境中避免误判客户机状态。结合 docs/interop/virtio-balloon-stats.rst、hw/virtio/virtio-balloon.c 与 include/standard-headers/linux/virtio_balloon.h 三份文件交叉阅读即可掌握从协议定义到 QMP 输出的完整链路。【免费下载链接】qemuOfficial QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website.项目地址: https://gitcode.com/gh_mirrors/qe/qemu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表