我正在使用async-profiler和perf并决定测量DirectByteBuffer
磁盘IO的内核活动。这是代码(用Scala编写,但是它的Java版本应该很明显):
val path = Paths.get("/tmp/test")
val buffer = ByteBuffer.allocateDirect(4096 * 4096)
def main(args: Array[String]): Unit = {
var fullReadsCount = 0
while (true) {
var bytesRead = 0
var ch: SeekableByteChannel = null
try {
ch = Files.newByteChannel(path)
while (bytesRead >= 0) {
bytesRead = ch.read(buffer)
buffer.clear()
}
} finally {
if (ch != null)
ch.close()
}
fullReadsCount += 1
if(fullReadsCount % 100 == 0) println(fullReadsCount)
}
}
我多次运行此代码,同时执行了perf
和async-profiler
,并注意到以下结果:
异步配置文件
$~/profiler.sh -i 28169 -d 30 <pid>
//.... stack traces ommited
ns percent samples top
264788732 61.02% 9317 copy_user_enhanced_fast_string_[k]
41510919 9.57% 1467 generic_file_read_iter_[k]
9333863 2.15% 331 find_get_entry_[k]
4181131 0.96% 148 __radix_tree_lookup_[k]
4057194 0.94% 143 copy_page_to_iter_[k]
1860485 0.43% 63 __d_lookup_rcu_[k]
1610407 0.37% 50 _raw_spin_unlock_irqrestore_[k]
性能sudo perf record -F 31499 -g -p <pid> -- sleep 30
在所有运行中,我平均注意到copy_user_enhanced_fast_string
和perf
async-profiler
与61.02%
的{{1}}百分比不同
问题: 为什么77.65%
和copy_user_enhanced_fast_string
采样的perf
的百分比不同?我试图提供相同的条件(频率和采样周期,但我没有同时模拟运行两个探查器。31499 Hz≈28169 nanos)。
还是我对结果的解释是错误的?
答案 0 :(得分:4)
所选的分析间隔(28μs)太短。
检查dmesg
-可能有类似内核的警告
perf interrupt took too long (18047 > 18000), lowering kernel.perf_event_max_sample_rate to 25000
async-profiler
与perf
的区别在于处理PMU事件的机制。 perf
只是在环形缓冲区中收集样本,而async-profiler向该进程发送信号以调用特定于应用程序的回调。通常,用户看不到任何差异,但是当分析频率太高时,信号可能会引入额外的噪声并影响流程调度。
我建议将分析间隔至少增加到100μs(10000 Hz)。这样可以使测量更可靠。