sendmsg +原始以太网+几个帧

我使用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 ,但是得到错误“message too long”,看起来像msghdr::msg_iov无法描述size > MTU

所以问题是可以立即从用户空间在Linux上发送多个原始以太网帧?

PS

我从文件中获得的数据(800KB) ,并将其读取到内存中。 因此, struct iovec对我有好处,我可以创build适当数量的以太网报头,并且iovec per 1500 packet一个iovec per 1500 packet ,一个指向数据,一个指向以太网报头。

哇。

我上一个公司做了实时的hidef视频编码硬件。 在实验室里,我们不得不通过一个绑定链接来爆发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要多100x-200x。

如何使用两个普通的write调用套接字? 一个用于标题,一个用于数据[ 全部 800KB]。 write可用于套接字,并没有EMSGSIZE错误或限制。

此外,为什么你需要你的头在一个单独的缓冲区? 当你分配你的缓冲区时,只需要:

 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 

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

您可以重复TCP / UDP与ETH的测量。 你可能会发现,它不会像你想象的那样买你的东西。 再一次,你能用精确的测量来证明吗?

我在上述公司工作的时候“发明了”这个算法,只是发现它已经是通过一个100Gb以太网NIC卡发送原始视频的视频标准的一部分,并且NIC在硬件上做了时间戳。

你可能要做的其他事情之一是添加一些油门控制。 这与Bittorrent的作用或PCIe总线的作用类似。

当PCIe总线节点首次启动时,它们将传送多少空闲的缓冲空间用于“盲目写入”。 也就是说,发送者可以自由地发送到这个, 没有任何ACK消息。 当接收机消耗其输入缓冲区时,它会周期性地向发送方发送ACK消息,消息的数量可以减少。 发件人可以将此值添加回盲写限制并继续。

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

UPDATE

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

你需要一个原始套接字并发送一个以太网帧。 您可以通过ifconfigSIOCSIFMTUioctl呼叫设置较大的MTU 减少开销。 我推荐ioctl 。 您可能不需要将MTU设置为800KB。 您的CPU的NIC卡有一个实际的限制。 你可以很容易地把MTU从1500增加到15000。 这可以将系统调用的开销减少10倍,并且可能“足够好”。

你可能将不得不使用sendto/sendmsg 。 这两个write调用基于转换为TCP / UDP。 但是,我怀疑sendmsgmsg_iov将比sendto有更多的开销。 如果你搜索,你会发现你想要使用sendto大部分示例代码。 sendmsg对你来说看起来好像少了一些开销,但是它可能会给内核带来更多的开销。 这是一个使用sendto的例子: http : //hacked10bits.blogspot.com/2011/12/sending-raw-ethernet-frames-in-6-easy.html

除了改善系统调用开销之外,更大的MTU 可能会提高“线路”的效率,尽管在您的使用情况下这似乎不成问题。 我有CPU + FPGA系统的经验和他们之间的沟通,但我仍然对你的一个评论“不使用电线”感到困惑。 连接到CPU的以太网引脚的FPGA我得到 – 排序。 更确切地说,你的意思是FPGA引脚连接到CPU的NIC卡/芯片的以太网引脚“

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

但是,我必须再次强调,在你盲目地尝试改进之前,你必须能够衡量你的表现

你有没有运行测试用例,我建议确定系统调用开销? 如果它足够小,试图优化它可能是值得的,而这样做可能实际上损害了其他领域的表现,在其他领域,当你开始时你并没有意识到。

举个例子,我曾经在一个有严重性能问题的系统上工作过,所以系统没有工作。 我怀疑串口驱动程序很慢,所以我从一个高级语言(如C)重新编译为汇编程序。

我把驾驶员的表现提高了2倍,但是对系统的性能改善不到5%。 事实证明, 真正的问题是, 其他代码正在访问不存在的内存,这只是造成总线超时,显着减慢了系统的速度(它不会产生一个中断,因此很容易在现代系统上找到这种中断)。

那时我才知道测量的重要性。 我根据一个有教养的猜测来做我的优化,而不是硬数据。 之后:经验教训!

现在,我从来没有尝试过大的优化,直到我可以先测量。 在某些情况下,我添加了一个“确定”的优化会使事情变得更好(例如内联函数)。 当我测量它( 因为可以测量它),我发现新的代码实际上比较 ,我不得不还原这个变化。 但是,这是重点:我可以用性能数据来证明/反驳这一点。

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

你在用什么FPGA(例如Xilinx,Altera)? 什么具体类型/部件号? 什么是最高时钟频率? FPGA是完全用于逻辑还是你内部还有一个CPU,比如microblaze,nios,arm? FPGA能够访问自己的DRAM(以及多少DRAM)?

如果增加MTU,FPGA可以从缓冲器/空间角度或时钟速度角度来处理? 如果你增加MTU,你可能需要添加一个ack / sync协议,正如我在原帖中所建议的。

目前,CPU正在对数据进行盲目写入,希望FPGA能够处理它。 这意味着你在CPU和FPGA之间有一个开放的竞争条件。

这可能被减轻,纯粹是作为发送小包的副作用。 如果你增加了太多的MTU,你可能会压倒FPGA。 换句话说,这是您试图优化的开销,使FPGA能够跟上数据速率。

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

发送到FPGA的数据的性质是什么? 你发送800KB,但多久?

我假设它不是 FPGA固件本身有几个原因。 你说固件已经快满了,正在接收以太网数据。 此外,固件通常通过I2C总线,ROM或FPGA编程器加载。 那么我正确吗?

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

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

所以,如果你想减少开销,从一个文件读取数据可能比应用程序生成数据要多得多(如果可能的话)。

内核的系统调用接口被设计成非常低的开销。 内核程序员(我碰巧是一个人)花了很多时间来确保开销很低。

你说你的系统正在利用大量的CPU时间来处理其他事情。 你能测量其他的东西吗? 你的应用程序结构如何? 有多少个进程? 多少个线程? 他们如何交流? 什么是延迟/吞吐量? 你可能会发现[很可能找到]更大的瓶颈,并重新编码这些,你会得到CPU使用率的总体减少, 远远超过你从MTU调整中获得的最大收益。

试图优化系统调用开销可能就像我的串口优化。 很多努力,但总体的结果是令人失望的。

在考虑性能时,从整个系统的角度来考虑是非常重要的。 在你的情况下,这意味着CPU,FPGA和其他任何东西。

你说CPU正在做很多事情。 可能/应该将这些算法中的一些进入FPGA? 他们的原因不是因为FPGA几乎没有空间,否则你会呢? FPGA固件100%完成了吗? 或者,是否有更多的RTL被写入? 如果FPGA的空间利用率达到90%,并且需要更多的RTL,那么您可能希望考虑转向具有更多逻辑空间的FPGA器件,这可能需要更高的时钟频率。

在我的视频公司,我们使用了FPGA。 我们使用了FPGA供应商拥有的最大/最快的最先进的部件。 我们还用逻辑空间的几乎100%,并要求该部分的最大时钟速率。 我们被供应商告知,我们是全球任何客户公司的FPGA资源的最大消费者。 正因为如此,我们紧张的供应商开发工具。 布局和路线经常会失败,必须重新运行才能获得正确的布局和时间。

所以,当FPGA几乎满逻辑时,布局布线可能难以实现。 这可能是考虑更大一部分的原因(如果可能的话)