send和sendmsg性能测试
1,摘要:测试send和sendmsg的性能,影响这两个函数性能主要有发送的字节大小,增加循环次数,从100到10000000(千万)
2,基本信息
cat /proc/cpuinfo查看CPU信息,如下:
Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz
cat /proc/version 查看操作系统内核版本,如下:
Linux version 3.10.0-327.el7.x86_64
cat /proc/meminfo查看内存信息,如下:
MemTotal: 131748016 kB
MemFree: 42526620 kB
MemAvailable: 60623924 kB
3,send性能测试
服务器端 : nc -lu 8888
客服端:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include<time.h> #include <sys/times.h> #include <unistd.h> //#define BUFSIZ 1024 #define recycle 1000000 static inline uint64_t rte_rdtsc(void) { union { uint64_t tsc_64; struct { uint32_t lo_32; uint32_t hi_32; }; }tsc; asm volatile("rdtsc": "=a" (tsc.lo_32), "=d" (tsc.hi_32)); return tsc.tsc_64; } int recycleSet[]={100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000}; int bufsizeSet[]={128,256,512,1024,2048,3072,4096}; int main(int argc,char *argv[]) { /*if(argc<3) { printf("paramaters error! ./socet_sendmsg 1000 1024"); return -1; } int recycle_times=atoi(argv[1]); int buf_len=atoi(argv[2]); */ int sockfd,numbytes; //char buf[BUFSIZ]; int sc_clk_tck; sc_clk_tck = sysconf(_SC_CLK_TCK); sc_clk_tck = sysconf(_SC_CLK_TCK); struct sockaddr_in their_addr; //printf("break! sc_clk_tck=%d\n",sc_clk_tck); while((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1); //printf("We get the sockfd~\n"); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(8888); their_addr.sin_addr.s_addr=inet_addr("192.168.10.8"); bzero(&(their_addr.sin_zero), 8); while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1); // printf("Get the Server~Cheers!\n"); 濉濞绔俊姣 // numbytes = recv(sockfd, buf, BUFSIZ,0);//妤娑? // buf[numbytes]='\0'; // printf("%s",buf); //clock_t start_time,end_time; // start_time=clock(); int buf_i=0; for(buf_i=0;buf_i<7;buf_i++){ int buf_len=bufsizeSet[buf_i]; char *buf=(char *)calloc(buf_len,sizeof(char)); int i=0; for(i=0;i<buf_len;i++) { buf[i]='a' + rand()%26; } buf[buf_len]='\0'; int recycle_i=0; for(recycle_i=0;recycle_i<11;recycle_i++){ int recycle_times=recycleSet[recycle_i]; struct timeval start_time,end_time; gettimeofday(&start_time,NULL); uint64_t start=rte_rdtsc(); for(i=0;i<recycle_times;i++) { numbytes = send(sockfd, buf, strlen(buf), 0); //numbytes=recv(sockfd,buf,BUFSIZ,0); //buf[numbytes]='\0'; //printf("send:%d\n",numbytes); } uint64_t end=rte_rdtsc(); //end_time=clock(); gettimeofday(&end_time,NULL); uint64_t duration=end-start; double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec); //printf("recycle_times=%d duration=%f numbytes=%d duration_rte=%f\n",recycle_times,duration_time,numbytes,duration/2.2); printf("%d,%d,%d, %f ,%f,%f\n",recycle_times,numbytes,buf_len,duration_time,duration/2.2,duration_time*1.0/recycle_times); } } close(sockfd); return 0; }
4,sendmsg性能测试(iovlen=1)
服务器端:
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> /************************************************************************************************************************ *************************************************************************************************************************/ int main(int argc, char *argv[]) { int fd, new_fd, struct_len, numbytes,i; struct sockaddr_in server_addr; struct sockaddr_in client_addr; char buff[BUFSIZ]; //struct msghdr msg; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8888); server_addr.sin_addr.s_addr = INADDR_ANY; // bzero(&(server_addr.sin_zero), 8); struct_len = sizeof(struct sockaddr_in); while((fd = socket(AF_INET,SOCK_DGRAM,0)) == -1); if (bind(fd, (struct sockaddr*)(&server_addr), struct_len) < 0) { fprintf(stderr, "bind fail\n"); exit(EXIT_FAILURE); } printf("Bind Success!\n"); // fd = socket(AF_INET, SOCK_DGRAM, 0); /*while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1); printf("Bind Success!\n"); while(listen(fd, 100) == -1); printf("Listening....\n"); printf("Ready for Accept,Waitting...\n"); new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len); */ //printf("Get the Client.\n"); // numbytes = send(new_fd,"Welcome to my server\n",21,0); while(1) { printf("recemsg\n"); struct msghdr msg; bzero(&msg,sizeof(struct msghdr)); msg.msg_name =&client_addr; msg.msg_namelen =sizeof(struct sockaddr_in); struct iovec io; io.iov_base =buff; io.iov_len =BUFSIZ; msg.msg_iov = &io; msg.msg_iovlen = 1; numbytes = recvmsg(fd,&msg,0); char * temp = msg.msg_iov[0].iov_base;//获取得到的数据 temp[numbytes] = '\0';//为数据末尾添加结束符 // printf("get %d message:%s", numbytes,temp); printf("get %d \n", numbytes); } // close(new_fd); close(fd); return 0; }
客服端:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include<time.h> #include <sys/times.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> //#define BUFSIZ 1024 #define recycle 1000000 static inline uint64_t rte_rdtsc(void) { union { uint64_t tsc_64; struct { uint32_t lo_32; uint32_t hi_32; }; }tsc; asm volatile("rdtsc": "=a" (tsc.lo_32), "=d" (tsc.hi_32)); return tsc.tsc_64; } int recycleSet[]={100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000}; int bufsizeSet[]={128,256,512,1024,2048,3072,4096}; int main(int argc,char *argv[]) { /*if(argc<3) { printf("paramaters error! ./socet_sendmsg 1000 1024"); return -1; } int recycle_times=atoi(argv[1]); int buf_len=atoi(argv[2]); */ int sockfd,numbytes; //char buf[BUFSIZ]; int sc_clk_tck; sc_clk_tck = sysconf(_SC_CLK_TCK); struct sockaddr_in their_addr; //printf("break! sc_clk_tck=%d\n",sc_clk_tck); while((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1); //printf("We get the sockfd~\n"); bzero(&their_addr, sizeof(their_addr)); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(8888); their_addr.sin_addr.s_addr=inet_addr("192.168.10.8"); //their_addr.sin_addr.s_addr=htonl(INADDR_ANY); //bzero(&(their_addr.sin_zero), 8); // while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1); // printf("Get the Server~Cheers!\n"); // numbytes = recv(sockfd, buf, BUFSIZ,0);//接收服务器端信息 // buf[numbytes]='\0'; // printf("%s",buf); //clock_t start_time,end_time; // start_time=clock(); int buf_i=0; for(buf_i=0;buf_i<7;buf_i++){ int buf_len=bufsizeSet[buf_i]; char *buf=(char *)calloc(buf_len,sizeof(char)); int i=0; for(i=0;i<buf_len;i++) { buf[i]='a' + rand()%26; } buf[buf_len]='\0'; struct msghdr msg; bzero(&msg,sizeof(struct msghdr)); //msg.msg_name = NULL; msg.msg_name = &their_addr; msg.msg_namelen = sizeof(struct sockaddr_in); struct iovec io; io.iov_base = buf; io.iov_len = buf_len; msg.msg_iov = &io; msg.msg_iovlen = 1; int recycle_i=0; for(recycle_i=0;recycle_i<11;recycle_i++){ int recycle_times=recycleSet[recycle_i]; struct timeval start_time,end_time; gettimeofday(&start_time,NULL); uint64_t start=rte_rdtsc(); for(i=0;i<recycle_times;i++) { //numbytes = send(sockfd, buf, strlen(buf), 0); numbytes = sendmsg(sockfd, &msg, 0); //numbytes=recv(sockfd,buf,BUFSIZ,0); //buf[numbytes]='\0'; //printf("send:%d\n",numbytes); } uint64_t end=rte_rdtsc(); //end_time=clock(); gettimeofday(&end_time,NULL); uint64_t duration=end-start; double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec); //printf("recycle_times=%d duration=%f numbytes=%d duration_rte=%f\n",recycle_times,duration_time,numbytes,duration/2.2); printf("%d,%d,%d, %f ,%f,%f\n",recycle_times,numbytes,buf_len,duration_time,duration/2.2,duration_time*1.0/recycle_times); } } close(sockfd); return 0; }
4,sendmsg性能测试(iovlen=4)
服务器端:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include<time.h> #include <sys/times.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> //#define BUFSIZ 1024 #define recycle 1000000 static inline uint64_t rte_rdtsc(void) { union { uint64_t tsc_64; struct { uint32_t lo_32; uint32_t hi_32; }; }tsc; asm volatile("rdtsc": "=a" (tsc.lo_32), "=d" (tsc.hi_32)); return tsc.tsc_64; } int recycleSet[]={100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000}; int bufsizeSet[]={128,256,512,1024,2048,3072,4096,5120,6144,7168,8192,9216,15000,150000}; #define BUF_CNT 14 int main(int argc,char *argv[]) { /*if(argc<3) { printf("paramaters error! ./socet_sendmsg 1000 1024"); return -1; } int recycle_times=atoi(argv[1]); int buf_len=atoi(argv[2]); */ int sockfd,numbytes; //char buf[BUFSIZ]; int sc_clk_tck; sc_clk_tck = sysconf(_SC_CLK_TCK); struct sockaddr_in their_addr; //printf("break! sc_clk_tck=%d\n",sc_clk_tck); while((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1); //printf("We get the sockfd~\n"); bzero(&their_addr, sizeof(their_addr)); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(9999); their_addr.sin_addr.s_addr=inet_addr("192.168.10.8"); //their_addr.sin_addr.s_addr=htonl(INADDR_ANY); //bzero(&(their_addr.sin_zero), 8); // while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1); // printf("Get the Server~Cheers!\n"); // numbytes = recv(sockfd, buf, BUFSIZ,0);//接收服务器端信息 // buf[numbytes]='\0'; // printf("%s",buf); //clock_t start_time,end_time; // start_time=clock(); int buf_i=0; for(buf_i=0;buf_i<14;buf_i++){ int buf_len=bufsizeSet[buf_i]; char *buf=(char *)calloc(buf_len,sizeof(char)); int i=0; for(i=0;i<buf_len;i++) { buf[i]='a' + rand()%26; } buf[buf_len]='\0'; struct msghdr msg; bzero(&msg,sizeof(struct msghdr)); //msg.msg_name = NULL; msg.msg_name = &their_addr; msg.msg_namelen = sizeof(struct sockaddr_in); struct iovec io[4]; io[0].iov_base = buf; io[0].iov_len = buf_len; io[1].iov_base = buf; io[1].iov_len = buf_len; io[2].iov_base = buf; io[2].iov_len = buf_len; io[3].iov_base = buf; io[3].iov_len = buf_len; msg.msg_iov = io; msg.msg_iovlen =4; int recycle_i=0; for(recycle_i=8;recycle_i<9;recycle_i++){ int recycle_times=recycleSet[recycle_i]; struct timeval start_time,end_time; gettimeofday(&start_time,NULL); uint64_t start=rte_rdtsc(); for(i=0;i<recycle_times;i++) { //numbytes = send(sockfd, buf, strlen(buf), 0);MSG_DONTWAIT numbytes = sendmsg(sockfd, &msg, 0); //numbytes=recv(sockfd,buf,BUFSIZ,0); //buf[numbytes]='\0'; //printf("send:%d\n",numbytes); } uint64_t end=rte_rdtsc(); //end_time=clock(); gettimeofday(&end_time,NULL); uint64_t duration=end-start; double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec); //printf("recycle_times=%d duration=%f numbytes=%d duration_rte=%f\n",recycle_times,duration_time,numbytes,duration/2.2); printf("%d,%d,%d, %f ,%f,%f\n",recycle_times,numbytes,buf_len,duration_time,duration/2.3,duration_time*1.0/recycle_times); } } close(sockfd); return 0; }
客户端:
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> /************************************************************************************************************************ 1、int socket(int family,int type,int protocol) family: 指定使用的协议簇:AF_INET(IPv4) AF_INET6(IPv6) AF_LOCAL(UNIX协议) AF_ROUTE(路由套接字) AF_KEY(秘钥套接字) type: 指定使用的套接字的类型:SOCK_STREAM(字节流套接字) SOCK_DGRAM protocol: 如果套接字类型不是原始套接字,那么这个参数就为0 2、int bind(int sockfd, struct sockaddr *myaddr, int addrlen) sockfd: socket函数返回的套接字描述符 myaddr: 是指向本地IP地址的结构体指针 myaddrlen: 结构长度 struct sockaddr{ unsigned short sa_family; //通信协议类型族AF_xx char sa_data[14]; //14字节协议地址,包含该socket的IP地址和端口号 }; struct sockaddr_in{ short int sin_family; //通信协议类型族 unsigned short int sin_port; //端口号 struct in_addr sin_addr; //IP地址 unsigned char si_zero[8]; //填充0以保持与sockaddr结构的长度相同 }; 3、int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen) sockfd: socket函数返回套接字描述符 serv_addr: 服务器IP地址结构指针 addrlen: 结构体指针的长度 4、int listen(int sockfd, int backlog) sockfd: socket函数绑定bind后套接字描述符 backlog: 设置可连接客户端的最大连接个数,当有多个客户端向服务器请求时,收到此值的影响。默认值20 5、int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen) sockfd: socket函数经过listen后套接字描述符 cliaddr: 客户端套接字接口地址结构 addrlen: 客户端地址结构长度 6、int send(int sockfd, const void *msg,int len,int flags) 7、int recv(int sockfd, void *buf,int len,unsigned int flags) sockfd: socket函数的套接字描述符 msg: 发送数据的指针 buf: 存放接收数据的缓冲区 len: 数据的长度,把flags设置为0 *************************************************************************************************************************/ int main(int argc, char *argv[]) { int fd, new_fd, struct_len, numbytes,i; struct sockaddr_in server_addr; struct sockaddr_in client_addr; char buff[BUFSIZ*10]; printf("BUFFSIZE %d\n",BUFSIZ); //struct msghdr msg; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(9999); server_addr.sin_addr.s_addr = INADDR_ANY; // bzero(&(server_addr.sin_zero), 8); struct_len = sizeof(struct sockaddr_in); while((fd = socket(AF_INET,SOCK_DGRAM,0)) == -1); if (bind(fd, (struct sockaddr*)(&server_addr), struct_len) < 0) { printf("bind error\n"); return -1; } printf("Bind Success!\n"); // fd = socket(AF_INET, SOCK_DGRAM, 0); /*while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1); printf("Bind Success!\n"); while(listen(fd, 100) == -1); printf("Listening....\n"); printf("Ready for Accept,Waitting...\n"); new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len); */ //printf("Get the Client.\n"); // numbytes = send(new_fd,"Welcome to my server\n",21,0); int cnt=0; while(1) { printf("recemsg\n"); struct msghdr msg; bzero(&msg,sizeof(struct msghdr)); msg.msg_name =&client_addr; msg.msg_namelen =sizeof(struct sockaddr_in); struct iovec io; io.iov_base =buff; io.iov_len =BUFSIZ*100; msg.msg_iov = &io; msg.msg_iovlen = 5; numbytes = recvmsg(fd,&msg,0); char * temp = msg.msg_iov[0].iov_base;//获取得到的数据 temp[numbytes] = '\0';//为数据末尾添加结束符 // printf("get %d message:%s", numbytes,temp); if(numbytes>0) cnt++; printf("get %d cnt %d\n", numbytes,cnt); } // close(new_fd); close(fd); return 0; }
6,send测试数据表
7,sendmsg测试数据表(iovlen=1)
7,sendmsg测试数据表(iovlen=4)
8,比较send,sendmsg(iovlen=1),sendmsg(iovlen=4)
9,用gettimeofday测试性能基本逻辑(gettimeofday和滴答数转化成时间基本差不多)
单位为:微秒
struct timeval start_time,end_time;
gettimeofday(&start_time,NULL);
uint64_t start=rte_rdtsc();
函数调用
uint64_t end=rte_rdtsc();
//end_time=clock();
gettimeofday(&end_time,NULL);
uint64_t duration=end-start;
double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec);
8,send和sendmsg性能测试比较(循环一千万次,算出一次时间开销(微秒))
结论:
1,send和sendmsg的性能基本一样
2,性能随字节成正比,比如128B~1.55微秒 ,256B~2.57微秒,1024B~8.72微秒,4096B~34.22微秒
3,sendmsg(iovlen=1)和sendmsg(iovlen=4)的在发送相同字节情况下,性能也是4倍,sendmsg在性能上并没得到优化