python - 测量小型应用程序的性能
问题描述
我为 Sway WM(https://swaywm.org)写了一个状态栏,基本上每秒打印一些信息(loadavg、cpu 使用情况、内存使用情况、时间……)。
该项目 ( https://gitlab.com/Yellowhat/statusbar ) 纯粹是为了了解 CI/CD 以及如何测量性能(如果可能在嘈杂的环境中)。
最初该项目是全部编写的,python
但前一段时间我决定在rust
(https://gitlab.com/Yellowhat/statusbar/-/tree/master/tools/rust)中编写一个功能等效的(它们打印出完全相同的信息)。
查看每秒执行的指令数( I refs
using ,精简版):cachegrind
python
: ~800krust
: ~35k
我可以得出结论,这个rust
版本比那个版本“轻”得多python
。
由于状态栏会在系统运行时持续运行,我想了解它对我的系统的影响。所以我决定python
在空闲时使用以下脚本监控我的系统(不要触摸电脑 1 小时,100% 亮度):
from time import sleep
while True:
stat = open("/proc/stat").readlines()[0].split()[1:8]
power = float(open("/sys/class/power_supply/BAT0/power_now").read().strip()) / 10**6
print(f"{stat},{power}")
sleep(1)
/proc/stat
返回花费了多少 CPU 时间 (jiffies):user
:在用户模式下执行的正常进程nice
: 在用户模式下执行的 niced 进程system
: 在内核模式下执行的进程idle
: 摆弄大拇指iowait
: 等待 I/O 完成irq
: 服务中断softirq
: 服务软中断
/sys/class/power_supply/BAT0/power_now
返回从电池中消耗了多少功率(微瓦)
我比较了4个案例:
- tty:启动计算机并运行脚本
tty
- sway : 启动电脑,启动
sway
(不带栏),打开终端并运行脚本 - sway barpy : 启动电脑,启动
sway
(带python
版本),打开终端运行脚本 - sway barrs:启动计算机,启动
sway
(使用rust
版本),打开终端并运行脚本
下图显示了SUM(user_t, nice_t, system_t, iowait_t, irq_t, softirq_t) - SUM(user_t0, nice_t0, system_t0, iowait_t0, irq_t0, softirq_t0)
,(所有未空闲的 CPU 花费了多少时间)-(测试开始时的初始值)与 4 种情况的时间:
如您所见,tty是最低的,其次是sway,但有趣的rust
是版本比那个高得多python
。
下图显示了 4 种情况下的功率与时间:
可以看到,tty的消耗最低,sway次之,非常接近rust
,python
最后。这是我所期望的结果。
第一张图表明,在这种情况下,rust
不比 轻python
。
是否有更可靠的方法来测量“轻”应用?我误解了/proc/stat
内容吗?
谢谢
更新 1
下图显示user_t - user_t0
, nice_t - nice_t0
,与和的system_t - system_t0
时间关系:python
rust
user
相反system
,nice
它们是相似的,并且对于rust
.
更新 2
正如 Peter Cordes 所建议的那样,我已经运行:
perf stat -a -d -e cpu-cycles,cycles,cycles:u,instructions,instructions:u -r 10 <binary>
下表总结了结果:
版本 | 期间 | CPU 周期 | 循环 | 周期:u | 指示 | 说明:u |
---|---|---|---|---|---|---|
Python | 0 | 285,248,768 | 285,492,709 | 215,681,759 | 323,852,866 | 278,792,657 |
Python | 60 | 3,038,749,610 | 3,046,770,477 | 1,360,477,472 | 2,425,399,588 | 1,612,134,730 |
Python | 120 | 5,802,965,874 | 5,818,929,489 | 2,496,192,062 | 4,536,305,443 | 2,890,941,664 |
锈 | 0 | 1,165,223 | 1,165,869 | 304,188 | 1,319,168 | 442,565 |
锈 | 60 | 3,791,712,516 | 3,799,515,523 | 1,654,232,537 | 3,355,917,423 | 2,073,096,815 |
锈 | 120 | 7,878,549,570 | 7,897,534,278 | 3,341,698,282 | 6,665,643,064 | 4,144,148,632 |
删除初始值(持续时间 = 0)并除以持续时间:
版本 | 期间 | CPU 周期 | 循环 | 周期:u | 指示 | 说明:u |
---|---|---|---|---|---|---|
Python | 60 | 45,891,681 | 46,021,296 | 19,079,929 | 35,025,779 | 22,222,368 |
Python | 120 | 45,980,976 | 46,111,973 | 19,004,253 | 35,103,771 | 21,767,908 |
锈 | 60 | 63,175,788 | 63,305,828 | 27,565,472 | 55,909,971 | 34,544,238 |
锈 | 120 | 65,644,870 | 65,803,070 | 27,844,951 | 55,536,032 | 34,530,884 |
同样,似乎该rust
版本运行的周期/指令比那个版本多python
。
更新 3
$ valgrind \
--tool=cachegrind \
--cachegrind-out-file=/dev/null \
--trace-children=yes \
--I1=32768,8,64 \
--D1=32768,8,64 \
--LL=8388608,16,64 \
--cache-sim=yes \
--branch-sim=yes \
<binary>
运行 120 秒:
python
版本:
I refs: 328,117,776
I1 misses: 5,268,249
LLi misses: 15,274
I1 miss rate: 1.61%
LLi miss rate: 0.00%
D refs: 135,851,173 (95,116,936 rd + 40,734,237 wr)
D1 misses: 4,717,331 ( 4,145,263 rd + 572,068 wr)
LLd misses: 167,298 ( 57,266 rd + 110,032 wr)
D1 miss rate: 3.5% ( 4.4% + 1.4% )
LLd miss rate: 0.1% ( 0.1% + 0.3% )
LL refs: 9,985,580 ( 9,413,512 rd + 572,068 wr)
LL misses: 182,572 ( 72,540 rd + 110,032 wr)
LL miss rate: 0.0% ( 0.0% + 0.3% )
Branches: 60,115,083 (56,103,351 cond + 4,011,732 ind)
Mispredicts: 5,661,255 ( 4,245,148 cond + 1,416,107 ind)
Mispred rate: 9.4% ( 7.6% + 35.3% )
rust
版本:
I refs: 100,950,027
I1 misses: 351,835
LLi misses: 5,859
I1 miss rate: 0.35%
LLi miss rate: 0.01%
D refs: 44,227,512 (24,903,985 rd + 19,323,527 wr)
D1 misses: 670,307 ( 341,521 rd + 328,786 wr)
LLd misses: 34,962 ( 20,657 rd + 14,305 wr)
D1 miss rate: 1.5% ( 1.4% + 1.7% )
LLd miss rate: 0.1% ( 0.1% + 0.1% )
LL refs: 1,022,142 ( 693,356 rd + 328,786 wr)
LL misses: 40,821 ( 26,516 rd + 14,305 wr)
LL miss rate: 0.0% ( 0.0% + 0.1% )
Branches: 19,868,173 (18,608,630 cond + 1,259,543 ind)
Mispredicts: 1,289,209 ( 771,555 cond + 517,654 ind)
Mispred rate: 6.5% ( 4.1% + 41.1% )
解决方案
推荐阅读
- spring - 在 RestController 中返回多个对象/dto 的最佳实践
- c# - 我在填充下拉列表时遇到问题,该列表的数据在 asp.net mvc 中的不同模型中引用?
- flutter - Flutter 将 SliverPersistentHeaderDelegate minExtent 设置为子高度
- android - 表 Contacts 没有名为 userId 的列(代码 1 SQLITE_ERROR):
- docker - 我应该为 docker 托管的 DNS 解决方案禁用 systemd-resolve 吗?
- android - RecyclerView ViewHolder 的新 Activity 卡在黑屏上
- android - Android RecyclerView 触发背景选择器/波纹以获取一些滚动视图
- angular - 出现错误:NG0303:无法绑定到“ng-If”,因为它不是“app-grocery”的已知属性
- android-studio - 从具有 ViewPager2 的 Fragment 中的 Fragment 调用方法
- python - 如何解决“ValueError:无法从重复轴重新索引”?