C 如何在性能事件打开时以恒定速率采样?

C 如何在性能事件打开时以恒定速率采样?,c,linux,linux-kernel,operating-system,perf,C,Linux,Linux Kernel,Operating System,Perf,我试图在linux上使用perf_事件监视进程的执行,并对其失效指令的数量进行采样。 我希望在一段时间内以固定、恒定的采样周期对流程进行采样 一切似乎都很顺利,我已经成功地编写了代码,它调用了perf\u event\u open(),并设置了两个不同的计数器: 前导一个,属于性能类型\u硬件类型,标识为性能计数\u硬件\u CPU \u周期,用作我的“采样”事件。我指定其采样周期为10000 slave one,表示失效指令数的事件(我通过传递其十六进制数指定其标识以执行事件,即0x00c4

我试图在linux上使用perf_事件监视进程的执行,并对其失效指令的数量进行采样。 我希望在一段时间内以固定、恒定的采样周期对流程进行采样

一切似乎都很顺利,我已经成功地编写了代码,它调用了
perf\u event\u open()
,并设置了两个不同的计数器:

  • 前导一个,属于
    性能类型\u硬件
    类型,标识为
    性能计数\u硬件\u CPU \u周期
    ,用作我的“采样”事件。我指定其采样周期为10000
  • slave one,表示失效指令数的事件(我通过传递其十六进制数指定其标识以执行事件,即
    0x00c4
Perf_事件正确地对目标进程进行采样,允许我通过内存的共享
mmap()ed
部分访问其采样

然后,我将获得的值写入一个文件,并将其保存为一个矩阵,而第n列对应第n个样本,每行对应一个全新的测量运行

我在此报告矩阵中的一些随机行:

910 1963 3159 4384 5631 6858 8114 9362 10303 15511 21270 26984 32818 38601 44157 49837 55500 
768 1924 3161 4404 5651 6890 8133 9370 10274 14987 20740 26539 32350 38133 43692 49360 55085 
759 1801 3025 4274 5518 6755 8001 9246 10264 14171 19871 25563 31362 37102 42663 48310 53980 
617 1459 2322 3135 3972 4741 5518 6260 7043 7850 8657 9446 10218 11339 14040 16389 18924 21325 23831 26581 29174 31774 34566 37294 39873 42588 45290 47869 50523 53334 55784 57535 
855 2006 3248 4483 5729 6951 8198 9440 10334 15637 21401 27168 32979 38799 44341 50065 55756 
688 1463 2242 2978 3738 4376 5094 5811 6467 7151 7814 8488 9042 9741 10278 12218 14425 16995 19598 22327 24941 27632 30176 32780 35289 37703 40501 43329 45939 49551 55116 
748 1929 3175 4423 5666 6911 8150 9392 10272 14469 20152 25922 31691 37510 43099 48732 54464 
775 1950 3190 4429 5674 6914 8157 9397 10275 15093 20848 26675 32437 38241 43764 49512 55129 
787 1840 2947 4192 5427 6656 7766 8885 9994 11547 17023 22712 28515 34282 40051 45726 51421 57066 
883 2073 3310 4558 5790 7033 8283 9532 10357 15754 21475 27231 33061 38831 44472 50195 55849 
798 1996 3239 4461 5706 6950 8199 9441 10275 15229 21009 26783 32626 38414 43977 49707 55429 
736 1486 2262 2863 3665 4388 4987 5707 6313 6892 7634 8355 9058 9730 10271 11794 14023 16123 17814 20313 22850 25413 27924 30670 33231 35726 38003 40310 42840 44565 46475 47660 51698 57085 
627 1814 3048 4296 5540 6776 8026 9273 10264 13855 19581 25328 31167 36929 42462 48098 53746 57523 
920 2062 3310 4547 5794 7029 8267 9517 10496 15891 21649 27425 33213 38931 44435 50107 55746 
问题是我得到了不同长度的行:(

我为不同的测量运行获取不同数量的样本

最终的值总是相同的(~55000),但在某些行中,我几乎获得了两倍的样本数。 我提出的唯一解释是内核有时会任意决定修改采样周期

这可能吗

在处理
性能事件时,如何确保
采样周期
在内核端保持不变

编辑:

正如所建议的,我已经调查了
dmesg
内核日志:我希望找到一条关于内核动态修改采样周期的消息,正如linux/4.11.3/kernel/events/core.c中的内核函数
perf_duration_warn()
中实现的那样,但是没有显示任何内容

为了尝试解决这个问题,我决定在开始测量之前修改
perf\u event\u max\u sample\u rate
perf\u cpu\u time\u max\u percent
值,如下所示:

sudo sysctl -w kernel/perf_cpu_time_max_percent=0
sudo sysctl -w kernel/perf_event_max_sample_rate=1000000
我还发现,我用来采样的时间事件会受到CPU频率缩放的影响。 为了避免该问题,在开始测量之前,我限制所有CPU使用powersave,恒定频率:

for (( i = 0; i < 8; i++ )); do
  sudo cpufreq-set -g powersave -c $((i))
done
有人知道我在哪里可以进一步调查这个问题吗

编辑3


我已将采样周期从10000增加到100000,以查看会发生什么情况:我得到较少的“较长”行,但问题仍然存在,并且我得到了不同长度的行不幸的是,

在perf和cpu之间有一层,结果不准确

如果使用的cpu是Intel,您可以使用Agner Fog提供的工具框架吗

根据我的经验,它很容易使用和准确


我已经用它做了一些优化。

我已经解决了这个问题

为了确保使用perf_事件系统调用在恒定时间段内进行有效采样,需要:

  • 使用
    perf\u event\u attr struct
    中的
    sample\u period
    字段指定事件采样周期。如中所述,您应注意该数字超过可表示为32位的值,否则系统将自动截断它
  • 不要使用
    perf\u event\u attr struct
    中的
    sample\u freq
    字段指定采样周期。如果这样做,内核将动态更改采样周期以达到所需的频率,如中所述
  • 使用
    dmesg
    内核日志检查:您不应该得到任何类型的消息。否则,正如Arnabjyoti Kalita所建议的,采样周期值可能太接近内核变量
    perf\u event\u max\u sample\u rate
    中设置的最大值。在这种情况下,最好的方法是使用
    sudo sysctl>修改内核变量-w kernel/perf_cpu_time_max_percent=0
    ,这样内核在默认情况下不会修改采样周期,即使这可能会导致计算机卡住。 内核实现此功能是为了避免在太多PMI(性能监视中断)占用太多计算时间时卡住。这些中断由perf_事件功能钩住,并在采样事件溢出超过指定的采样周期值时触发。 有关perf_事件内核变量的更多信息,请参阅linux版本/documentation/sysctl/kernel.txt的内核源代码中的文档
  • 使用
    sudo cpufreq Set-g powersave-c$((i))
    将cpu频率设置为常量,这样您的cpu测量不会受到影响 通过频率缩放
  • 计算样本之间采样事件值的差异,并验证其是否(在小误差范围内)等于指定的采样周期
我问这个问题是因为我认为获得不同数量的样本与内核修改采样周期有关

不是。(可能是,但对我来说不是)

我之所以得到不同数量的样本,是因为任何类型的受监视线程在执行期间可能需要不同的执行时间。 对于那些“更长”的行,我确实获得了更大的时间值。 这是因为进程可能偶尔会出现一些缓存未命中或不同的预测失误分支

在这方面需要做的进一步工作可能是:

  • 使用其他时间事件对流程进行采样并监控差异
  • 使用其他计数器,检测导致某些运行的执行时间较长的原因
如果有人发现新信息
880 2064 3316 4582 5837 7088 8339 9595 10585 15868 21519 27263 33080 38859 44472 50216 55836 
927 2084 3324 4574 5815 7050 8303 9544 10683 16008 21743 27449 33213 38982 44511 50262 55965 
749 1825 3063 4306 5575 6818 8070 9317 10262 13926 19637 25396 31207 36995 42539 48096 53800 
629 1466 2323 3130 3926 4702 5439 6198 6918 7516 8114 8708 9351 10034 10734 12957 15283 17657 20200 22771 25464 28114 30451 32899 35225 37775 40371 43050 45609 48342 53820 
886 2063 3299 4208 5006 5814 6683 7565 8435 9336 10130 11222 13600 17364 23080 28853 34643 40365 45965 51625 57237 
821 2001 3251 4495 5733 6986 8247 9480 10265 12197 14699 17284 19897 22463 25141 28072 30695 33320 35964 38750 44183 49872 55515 
917 2071 3320 4562 5801 7029 8275 9508 10509 15865 21575 27317 33118 38916 44566 50256 55923 
472 1573 2806 4044 5270 6514 7743 8977 10217 13221 18923 24610 30389 36127 41717 47398 53076 57518 
924 1980 3225 4477 5712 6946 8183 9435 10353 15575 21318 27078 30246 32751 35310 37808 40322 42769 45306 47800 50340 52852 55395 57499 
932 2038 3270 4527 5655 6907 8030 9139 10237 13390 18965 24708 30389 36115 41719 47397 53030 57520 
927 2088 3327 4581 5826 7078 8316 9549 10692 16007 21726 27449 33235 39001 44564 50225 55890 
582 1405 2263 3061 3859 4651 5370 6170 6861 7461 8017 8601 9153 9808 10281 12318 14509 16810 19173 21820 24183 26912 29796 32447 34809 37347 39652 42216 44943 47728 50588 53182 57081 
903 2065 3320 4546 5795 7025 8272 9515 10294 15324 21081 26863 32644 38439 43975 49714 55388 
921 2094 3325 4571 5810 7045 8296 9548 10759 16134 21869 27560 33412 39154 44837 50581 56307 
860 2049 3284 4525 5771 7025 8283 9532 10415 15646 21325 27056 32827 38560 44065 49691 55352 
953 2124 3368 4610 5844 7071 8317 9575 10790 16141 21889 27642 33406 39151 44725 50435 56092 
921 2098 3338 4529 5311 6160 7030 7910 8792 9644 10293 12630 14972 17493 20388 26173 31915 37689 43267 48951 54696 
575 1384 2040 2841 3511 4068 4680 5386 6086 6677 7244 7828 8476 9104 9761 10279 11976 14187 16747 19192 21859 24662 26853 29386 31702 34421 36952 39444 41934 44699 47371 49965 52794 57509 
925 2101 3333 4575 5814 7066 8318 9562 10849 16188 21910 27648 33348 39069 44626 50245 55877 
591 1462 2321 3140 3975 4731 5494 6279 7042 7684 8252 8831 9415 10066 10793 13202 15480 17800 20151 22779 25268 27824 30673 33340 35680 38182 40851 43263 45995 48661 51409 54078 56696 
885 1927 3041 4157 5024 5779 6615 7473 8289 9124 9883 10440 12771 17987 23720 29495 35303 40764 46468 52157 57485