我正在尝试优化我编写的程序,该程序旨在通过将数据包发送到指定的MAC地址来复制网络流。
我的程序中负责发送和删除流的主循环如下:
while (size != 0 || response) {
for (i = 0; size != 0 && i < size; ++i) {
curFlow = *pCurFlow;
while (curFlow.cur_time < now) {
// Sending Packet
sendto(sockfd, curFlow.buff, curFlow.length, 0, \
memAddr, sAddrSize);
// Adjusting Packet Attributes
curFlow.packets_left -= 1;
curFlow.cur_time += curFlow.d_time;
// If the packet has no packets left, delete it
if (!curFlow.packets_left) {
pCurFlow -> last -> next = pCurFlow -> next;
pCurFlow -> next -> last = pCurFlow -> last;
size -= 1;
break;
}
}
*pCurFlow = curFlow;
pCurFlow = pCurFlow -> next;
}
}
我已经开始使用性能分析器来记录我正在执行的函数调用类型以及每个开销有多昂贵。但是,每次我要求perf给我报告时,结果都像这样:
Overhead Command Shared Object Symbol
15.34% packetize /proc/kcore 0x7fff9c805b73 k [k] do_syscall_64
6.19% packetize /proc/kcore 0x7fff9d20214f k [k] syscall_return_via_sysret
5.98% packetize /proc/kcore 0x7fff9d1a3de6 k [k] _raw_spin_lock
5.29% packetize /proc/kcore 0x7fffc0512e9f k [k] mlx4_en_xmit
5.26% packetize /proc/kcore 0x7fff9d16784d k [k] packet_sendmsg
(注意:“ packetize”是我的程序的名称)
我的问题是,“ do_syscall_64”到底是什么??经过研究后,该特定功能似乎是用作中断请求的内核工具。
此外,我发现目录/ proc / kcore负责内存管理的某些组件,尽管在故意用内存引用对程序进行洗劫后,与程序一起使用的动态库是唯一增加的开销性能报告。
如果您对我有任何建议,请告诉我。谢谢!
答案 0 :(得分:3)
这不是中断请求;是从syscall
入口点调用的C函数,该C函数分派到适当的C函数,该C函数实现由用户空间传递的寄存器选择的系统调用。
在这种情况下大概为sys_sendto
。
在旧版Linux中,x86-64 syscall
入口点直接使用了函数指针的系统调用表(例如,如this Q&A所示,其中只有32位入口点int 0x80
使用了C包装函数)。
但是随着Spectre和Meltdown缓解措施的更改,本机64位系统调用入口点(从64位用户空间进入64位内核)也使用C包装器围绕系统调用分派。这允许使用C宏和gcc提示在间接分支之前控制推测障碍。 do_syscall_64
on github的当前Linux版本是一个非常简单的功能;除非nr = array_index_nospec(nr, NR_syscalls);
比我在您的CPU上所期望的要昂贵得多,否则它本身就会获得如此多的周期,这有点令人惊讶。
在手写asm syscall入口点肯定发生了昂贵的事情,例如编写刷新分支预测缓存的MSR。哦,也许缺少良好的分支预测会在此后调用的第一个C函数中花费额外的周期。
减轻“幽灵/崩溃”的影响使系统调用密集型工作负载遭受重创。尝试在禁用其中一些启动和/或完全没有该代码的较旧内核下启动。
Meltdown / L1TF / etc等在最新的Intel CPU中已完全固定,而没有性能成本,因此禁用此替代方法可能会为您提供一些线索,让您从全新CPU中获得多少收益。
(Spectre仍然是一个非常棘手的问题,无法通过对装载端口进行局部更改来轻松解决。IDK详细说明了各种缓解微码是否有效的缓解策略在各种CPU上的有效性。 )