双线程,一个生产数据放入kfifo,一个从kfifo取出数据,通过套接字发送。最终测试出来速度只能达到400MB/S。(kfifo出队64KB数据要100us)
之后我将生产者做了更改,让它只更新队首的in指针,不做数据拷贝,此时速度能达到1000MB/S。(kfifo出队64KB数据只要10us)
我怀疑是生产者生产数据写入队列时,导致消费者所在的cpu cache失效,然后cache未命中导致速度骤降。但是不知道怎么解决这个问题。
在网上搜索答案,但是没有找到类似情况。看到有一个和我问题应该比较类似的,但是没有找到解决方法。
《请问为何tcp send第一次时很慢, 第二次时很快呢?》
https://www.oschina.net/question/2897213_2193602
#include "szg_common.h"
#include "szg_kfifo.h"
#include "szg_socket.h"
/**kfifo
* 队列是将linux内核中的kfifo移到了这里来用,用malloc来替代内核中的kmalloc
* 此代码(发送端)运行在NXP T4240上,系统linux,万兆网卡。
* 接收端软件运行在PC上,系统windows10,万兆网卡。
*
* 1.正常出入队,kfifo总大小64M 元素大小256bytes 期望出队和期望入队都是256个元素
* 速度400MB/S 出队64k要100us send要50us
* 2.注释掉kfifoin中的两行memcpy(szgKfifoCopyIn中的),让其只更新队首in指针
* 速度1000MB/S 出队64k要10us send要50us
*
*
*/
#define KFIFO_SEND_SIZE 0x10000 //64k
#define FIFO_IN 0x100 //每次入队时期望入队的元素个数:256个(即256*256 = 64k)
#define FIFO_OUT 0x100 //每次出队时期望出队的元素个数:256个(即256*256 = 64k)
#define FIFO_E_SIZE 0x100 //元素大小:256byte
#define FIFO_SIZE 0x4000000 //总大小:64Mbyte (256*256*1024个)
kfifo testkFifo;
void *szgTestKfifoThread(void *param)
{
UINT32 ret;
char data_buf[KFIFO_SEND_SIZE] = {0};
while(TRUE)
{
ret = szgKfifoIn(&testkFifo,data_buf,FIFO_IN);
if(ret == 0)
{
pthread_yield();
//usleep(2);
}
}
}
int kfifo_test(void)
{
INT32 listenFd;
INT32 connectFd;
INT32 ret;
UINT32 clientIp;
pthread_t threadId;
pthread_attr_t attr;
struct timeval start,end;
char send_buf[KFIFO_SEND_SIZE];
memset(send_buf,1,KFIFO_SEND_SIZE);
signal(SIGPIPE,SIG_IGN);
/**
* 初始化kfifo
* 总大小 64M
* 元素大小 256byes
* 元素个数 256*1024个
* 出队,入队都是期望256个元素,不到256个有多少出多少,实际个数作为返回值返回
*/
ret = szgKfifoAlloc(&testFifo,FIFO_SIZE/FIFO_E_SIZE,FIFO_E_SIZE);
CHECK_EXIT(ret == ERROR, "fifo init err!");
/*创建线程,线程分离*/
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
if (0 != pthread_create(&threadId,&attr, (void *)szgTestKfifoThread,NULL))
{
SZG_LOG(SZG_LOG_ERR,"Create Thread data_filter_thread Fail \n");
return ERROR;
}
/*服务器初始化 端口6101 发送缓存2M 接收缓存1M(2M/2)*/
listenFd = szgSockInit(NULL,6101,0x200000);
CHECK_EXIT(listenFd < 0, "socket error");
while(TRUE)
{
printf("wait connect\n");
/*客户端ip通过&clientIp返回(其实下面没用到)*/
connectFd = szgSockAccept(listenFd,&clientIp);
if (connectFd < 0)
{
SZG_LOG(SZG_LOG_ERR,"server Accept Failed!/n");
return 0;
}
while(TRUE)
{
//gettimeofday(&start,NULL);
/*出队 256*256 */
ret = szgKfifoOut(&testkFifo,send_buf,FIFO_OUT);
if(ret == 0)//没有数据
{
pthread_yield();
continue;
//usleep(2);
}
//gettimeofday(&end,NULL);
//printf("kfifo time %lu us \n",(1000000*(end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec)));
/*发送64k*/
//gettimeofday(&start,NULL);
ret = szgSendData(connectFd,send_buf,ret*FIFO_E_SIZE);
if(ret == ERROR)
{
SZG_LOG(SZG_LOG_ERR,"szgSendData data error\n");
break;
}
//gettimeofday(&end,NULL);
//printf("send time %lu us \n",(1000000*(end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec)));
}
}
return 0;
}