c++ - sendmsg +原始以太网+几帧

标签 c++ c linux

我使用linux 3.x和现代glibc(2.19)

我想发送几个以太网帧,而无需从内核/用户空间来回切换。

我有MTU = 1500,我想发送800 KB
我这样初始化接收者地址:

struct sockaddr_ll socket_address;
socket_address.sll_ifindex = if_idx.ifr_ifindex;
socket_address.sll_halen = ETH_ALEN;
socket_address.sll_addr[0] = MY_DEST_MAC0;
//...

之后,我可以调用sendto/sendmsg 800KB / 1500 ~= 500次,并且一切正常,但这需要用户空间<->内核协商〜每秒500 * 25次。我要避免它。

我尝试使用适当的信息init struct msghdr::msg_iov
但是出现错误“消息太长”,看起来msghdr::msg_iov无法用size > MTU描述某些内容。

因此,是否有可能在Linux上一次从用户空间发送许多原始以太网帧?

聚苯乙烯

我从文件中获取数据(800KB),并将其读取到内存中。因此,struct iovec对我很有用,我可以创建适当数量的以太网头,并且必须iovec per 1500 packet,一分指向数据,一分指向以太网 header 。

最佳答案



我的上一家公司制造了实时Hidef视频编码硬件。在实验室中,我们必须通过绑定(bind)链接以每秒200MB的速度传输数据,因此我对此有一些经验。以此为基础。

在调整之前,您必须先进行测量。您不想执行多个系统调用,但是可以通过计时测量证明开销很大吗?

我在clock_gettime周围使用了一个包装例程,该例程以纳秒级精度返回一天中的时间(例如(tv_sec * 100000000) + tv_nsec)。称此为“nanotime”。

因此,对于任何给定的系统调用,您都需要进行以下测量:

tstart = nanotime();
syscall();
tdif = nanotime() - tstart;

对于send/sendto/sendmsg/write,这样做会减少数据量,因此您可以确定自己没有阻塞[或使用O_NONBLOCK(如果适用)]。这给您系统调用的开销

您为什么直接进入以太网框架? TCP [或UDP]通常足够快,现代NIC卡可以在硬件中进行信封包装/打包。我想知道是否存在需要以太网框架的特定情况,还是您没有获得想要的性能并提出解决方案。请记住,您的速度为800KB/s(〜1MB/s),而我的项目比TCP的速度要高100-200倍。

对套接字使用两个简单的write调用怎么样?一个用于标题,一个用于数据[全部800KB]。 write可以在套接字上使用,没有EMSGSIZE错误或限制。

此外,为什么还要将 header 放在单独的缓冲区中?分配缓冲区时,只需执行以下操作:
datamax = 800 * 1024;  // or whatever
buflen = sizeof(struct header) + datamax;
buf = malloc(buflen);

while (1) {
    datalen = read(fdfile,&buf[sizeof(struct header)],datamax);
    // fill in header ...
    write(fdsock,buf,sizeof(struct header) + datalen);
}

即使在以太网框架的情况下也可以使用。

还可以做的一件事情是使用setsockopt来增加套接字的内核缓冲区的大小。否则,您可以发送数据,但是在接收者将其耗尽之前,它将被丢弃到内核中。在下面的更多内容。

要测量导线的性能,请在标题中添加一些字段:
u64 send_departure_time;  // set by sender from nanotime
u64 recv_arrival_time;  // set by receiver when the packet arrives

因此,发件人设置了出发时间并确实写了[只是做这个测试的标题]。将此数据包称为Xs。接收器在到达时对其进行标记。接收方立即向发送方发回一条消息,称为发送方Xr,带有离开戳和Xs的内容。当发件人收到此邮件时,它将在到达时间上加盖戳记。

有了以上内容,我们现在有了:
T1 -- time packet Xs departed sender
T2 -- time packet Xs arrived at receiver
T3 -- time packet Xr departed receiver
T4 -- time packet Xr arrived at sender

假设您在相对安静的连接上进行此操作,几乎没有其他流量,并且知道链路速度(例如1 Gb/s),那么使用T1/T2/T3/T4可以计算开销。

您可以重复测量TCP/UDP与ETH。您可能会发现,它并没有像您想的那样为您买很多东西。再一次,您可以通过精确的测量来证明吗?

我在上述公司工作时“发明”了这种算法,但发现它已经成为通过100Gb以太网NIC卡发送原始视频的视频标准的一部分,而NIC在硬件上加了时间戳。

您可能要做的另一件事是添加一些 throttle 控制。这类似于bittorrent或PCIe总线的功能。

当PCIe总线节点首次启动时,它们会传达它们有多少可用缓冲区空间可用于“盲写”。也就是说,发件人可以自由地发送大量消息,而无需任何ACK消息。当接收器耗尽其输入缓冲区时,它会定期向发送方发送ACK消息,其中包含其能够耗尽的字节数。发送者可以将此值加回到盲写限制并继续操作。

为了您的目的,盲写限制是接收者的内核套接字缓冲区的大小。

更新

根据您的评论中的一些其他信息[实际系统配置,应该以更完整的形式作为对您问题的底部编辑,]。

您确实需要原始套接字并发送以太网帧。您可以通过ifconfig或使用ioctlSIOCSIFMTU调用设置更大的MTU来减少开销。我推荐ioctl。您可能不需要将MTU设置为800KB。 CPU的NIC卡有实际限制。您可以轻松地将MTU从1500增加到15000。这将使系统调用开销减少10倍,并且可能“足够好”。

您可能必须使用sendto/sendmsg。这两个write调用基于对TCP/UDP的转换。但是,我怀疑带有sendmsgmsg_iov将比sendto拥有更多的开销。如果您进行搜索,则会发现大多数想要使用的示例代码都使用sendtosendmsg对您来说似乎减少了开销,但可能会导致内核更多的开销。这是一个使用sendto的示例:http://hacked10bits.blogspot.com/2011/12/sending-raw-ethernet-frames-in-6-easy.html

除了改善系统调用开销外,较大的MTU可能还会提高“连线”的效率,即使这在您的用例中似乎不是问题。我在CPU + FPGA系统以及它们之间的通信方面有经验,但是您对“不使用电线”的评论之一仍然感到困惑。 FPGA连接到我得到的CPU的以太网引脚上。更准确地说,您是指将FPGA引脚连接到NIC卡/CPU芯片的以太网引脚吗?

是否在同一块PC板上的CPU/NIC和FPGA引脚通过PC板走线连接?否则,我不理解“不使用电线”。

However, once again, I must say that you must be able to measure your performance before you blindly try to improve it.



您是否运行了我建议的用于确定系统调用开销的测试用例?如果它足够小,尝试对其进行优化可能不值得,并且这样做实际上可能会在开始时没有意识到的其他 Realm 严重损害性能。

例如,我曾经在一个存在严重性能问题的系统上工作,以至于该系统无法正常工作。我怀疑串行端口驱动程序运行缓慢,因此我将其从高级语言(例如C)重新编码为汇编器。

我将驱动程序性能提高了2倍,但对系统的性能改进却不到5%。事实证明,真正的问题是其他代码正在访问不存在的内存,这仅导致总线超时,从而显着降低了系统速度(它没有产生像在现代系统上那样容易找到的中断)。

那时我才知道测量的重要性。我是根据有根据的猜测而不是硬数据进行优化的。之后:吸取教训!

如今,直到可以先进行衡量,我才尝试进行大型优化。在某些情况下,我添加了“可以确保”将使事情变得更好的优化(例如,内联函数)。当我测量它(并且因为我可以测量它)时,我发现新代码实际上要慢一些,因此我必须还原更改。但是,这才是重点:我可以用硬性能数据来证明/证明这一点。

您正在使用哪个CPU:x86,arm,mips等。在什么时钟频率下?多少DRAM?多少个核心?

您正在使用什么FPGA(例如Xilinx,Altera)?具体的型号/零件号是什么?最大时钟速率是多少? FPGA是否完全专注于逻辑,或者您内部还具有CPU,例如Microblaze,Nios,arm? FPGA是否可以访问其自己的DRAM(以及多少DRAM)?

如果增加MTU,FPGA可以从缓冲区/空间的 Angular 还是从时钟速度的 Angular 来处理它?如果增加MTU,则可能需要添加ack/sync协议(protocol),如我在原始帖子中建议的那样。

当前,CPU正在对数据进行盲写,希望FPGA可以处理它。这意味着您在CPU和FPGA之间处于开放竞争状态。

纯粹作为发送小数据包的副作用,可以缓解这种情况。如果增加的MTU过多,可能会使FPGA瘫痪。换句话说,正是您要进行优化的非常大的开销,使FPGA可以跟上数据速率。

这就是盲目优化的意想不到的后果。它可能具有意想不到的副作用。

发送到FPGA的数据的本质是什么?您正在发送800KB,但是多久发送一次?

由于某些原因,我认为它不是FPGA固件本身。您说固件已经快满了(正在接收以太网数据)。同样,通常通过I2C总线,ROM或FPGA编程器加载固件。所以,我正确吗?

您正在从文件将数据发送到FPGA。这意味着它在CPU应用程序启动时仅发送一次。那是对的吗?如果是这样,则不需要优化,因为它的启动/启动成本对运行的系统影响很小。

因此,我必须假设该文件被加载了很多次,可能每次都加载了一个不同的文件。那是对的吗?如果是这样,您可能需要考虑read syscall的影响。不仅来自系统调用开销,而且具有最佳读取长度。例如,IIRC,磁盘到磁盘或文件到文件的复制/传输的最佳传输大小为64KB,具体取决于文件系统或底层磁盘的特性。

因此,如果您希望减少开销,那么从文件中读取数据可能比让应用程序生成数据要多得多(如果可能)。

内核syscall接口(interface)被设计为非常低的开销。内核程序员(我碰巧是一个)花费大量时间来确保开销很低。

您说您的系统将大量CPU时间用于其他方面。你能衡量其他事情吗?您的应用程序如何组织?多少个过程?有多少个线程?他们如何沟通?什么是等待时间/吞吐量?您可能可以找到[可能找到]较大的瓶颈并重新编码,从而使CPU使用率的总体下降幅度远远超过MTU调整所带来的最大 yield 。

尝试优化系统调用开销可能就像我的串行端口优化一样。尽管付出了很多努力,但总体结果还是令人失望的。

在考虑性能时,从整体系统的 Angular 考虑它很重要。在您的情况下,这意味着CPU,FPGA以及其中的其他任何东西。

您说CPU正在做很多事情。这些算法中的一些可以/应该进入FPGA吗?是不是不是因为FPGA的空间几乎不足,否则会这样吗? FPGA固件是否已100%完成?或者,还有更多的RTL要编写吗?如果您在FPGA中的空间利用率为90%,并且您需要更多的RTL,则您可能希望考虑使用一个具有更大逻辑空间的FPGA部件,并且时钟频率可能更高。

在我的视频公司中,我们使用了FPGA。我们使用了FPGA供应商拥有的最大/最快的最新技术部件。我们实际上还使用了100%的逻辑空间,并要求该部件的最大时钟速率。该供应商告诉我们,我们是其全局任何客户公司中FPGA资源的最大消费者。因此,我们使供应商的开发工具紧张。布局布线通常会失败,必须重新运行才能获得正确的布局并满足时间要求。

因此,当FPGA几乎充满逻辑时,可能很难实现布局布线。 [如果可能的话]可能会考虑考虑较大的部分

关于c++ - sendmsg +原始以太网+几帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26912561/

相关文章:

c - 将硬盘上文件中的空格替换为 %20

linux - 发现/proc/mounts 的 "true"大小

c++ - 如何将图片放大到 300 DPI?

c++ - 继承C++中的重载

c中的字符指针

c - 内核中的 Futex 和阻塞

linux - 简单的 linux 重定向

c - 初始化 termios 结构以作为 VT100 工作

c++ - 打印第 N 个素数的代码

c++ - 作为参数传递时如何在不更改原始值的情况下附加到字符串?