use*_*558 20 linux kernel mmap splice zero-copy
在最初的vmsplice()实现中,有人建议如果你有一个用户区缓冲区2x可以容纳管道的最大页数,那么缓冲区后半部分成功的vmsplice()将保证内核完成使用缓冲区的前半部分.
但事实并非如此,特别是对于TCP,内核页面将被保留,直到从另一方接收到ACK.修复这个问题是未来的工作,因此对于TCP,内核仍然需要从管道中复制页面.
vmsplice()有一个SPLICE_F_GIFT选项可以处理这个,但问题是这暴露了另外两个问题 - 如何有效地从内核获取新页面,以及如何减少缓存垃圾.第一个问题是mmap需要内核清除页面,第二个问题是虽然mmap可能会使用内核中的花式kscrubd功能,但这会增加进程的工作集(缓存垃圾).
基于此,我有以下问题:
mmap/ vmsplice/ splice/ munmap目前在TCP服务器中进行零复制的最佳实践还是今天我们有更好的选择?是的,由于TCP套接字在不确定的时间内保留页面,因此您无法使用示例代码中提到的双缓冲方案.此外,在我的用例中,页面来自循环缓冲区,因此我无法将页面提供给内核并分配新页面.我可以验证我在收到的数据中看到数据损坏.
我使用轮询TCP套接字的发送队列的级别,直到它耗尽为0.这修复了数据损坏但是次优,因为将发送队列排到0会影响吞吐量.
n = ::vmsplice(mVmsplicePipe.fd.w, &iov, 1, 0);
while (n) {
// splice pipe to socket
m = ::splice(mVmsplicePipe.fd.r, NULL, mFd, NULL, n, 0);
n -= m;
}
while(1) {
int outsize=0;
int result;
usleep(20000);
result = ::ioctl(mFd, SIOCOUTQ, &outsize);
if (result == 0) {
LOG_NOISE("outsize %d", outsize);
} else {
LOG_ERR_PERROR("SIOCOUTQ");
break;
}
//if (outsize <= (bufLen >> 1)) {
if (outsize == 0) {
LOG("outsize %d <= %u", outsize, bufLen>>1);
break;
}
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3453 次 |
| 最近记录: |