文章

2026-1-18-io_uring性能测试与epoll的对比

2026-1-18-io_uring性能测试与epoll的对比

io_uring的测试工具test_qps_tcpclient

通过编写命令行测试工具来对该io_uring服务器进行测试。要支持类似这样的效果:

1
./test_qps_tcp_client -s 127.0.0.1 -p 2048 -t 50 -c 100 -n 10000

-s:服务器地址 -p:端口号 -t:线程数量 -c:连接数量 -n:请求数量

test_context_t 结构体

将这些信息存在一个结构体中

1
2
3
4
5
6
7
8
9
10
typedef struct test_context_s{
    char serverip[16];
    int port;
    int threadnum;
    int connection;
    int requestion;
#if 1
    int failed;
#endif
}test_context_t;

main()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    int ret = 0;
    test_context_t ctx = {0};
    int opt;
    /* getopt函数:
    	"a"		支持 -a,无参数
		"b:"	支持 -b 参数
		"abc"	支持 -a -b -c
		"a:b:c"	-a arg -b arg -c arg
	*/
    while( (opt = getopt(argc,argv,"s:p:t:c:n:?")) != -1){
        switch(opt){
            case 's':
                printf("-s: %s\n",optarg);
                strcpy(ctx.serverip, optarg);
                break;
            case 'p':
                printf("-p: %s\n",optarg);
                ctx.port = atoi(optarg);
                break;
            case 't':
                printf("-t: %s\n",optarg);
                ctx.threadnum = atoi(optarg);
                break;
            case 'c':
                printf("-c: %s\n",optarg);
                ctx.connection = atoi(optarg);
                break;
            case 'n':
                printf("-n: %s\n",optarg);    
                ctx.requestion = atoi(optarg);
                break;
            default:
                return -1;
        }
    }
    //开threadnum个线程
    pthread_t *ptid = malloc(sizeof(pthread_t)*ctx.threadnum);
    int i = 0;
    struct timeval tv_begin; 
    gettimeofday(&tv_begin, NULL);
    for(i = 0; i < ctx.threadnum; i++){
        pthread_create(&ptid[i], NULL, test_qps_entry, &ctx);
    }
    for(i = 0; i < ctx.threadnum; i++){
        pthread_join(ptid[i], NULL);
    }
    struct timeval tv_end;
    gettimeofday(&tv_end, NULL);

    int time_used = TIME_SUB_MS(tv_end, tv_begin);
     
    printf("success: %d, failed: %d, time_used: %d\n", ctx.requestion - ctx.failed, ctx.failed, time_used);
clean:
    free(ptid);
    return 0;

test_qps_entry() 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void *test_qps_entry(void *arg){
    test_context_t *pctx = (test_context_t *)arg;
    // 连接对应的tcp服务器。
    int connfd = connect_tcpserver(pctx->serverip, pctx->port);
    if(connfd < 0){
        printf("connect_tcpserver failed\n");
        return NULL;
    }
    int count = pctx->requestion / pctx->threadnum;
    int i = 0;
    int res;
    while(i++ < count){
    	//发送与接收数据时的数据包
        res = send_recv_tcppkt(connfd);
        if(res != 0){
            printf("send_recv_tcppkt failed!");
            pctx->failed++;
            continue;
        }
    }
    return NULL;
}

connect_tcpserver() 函数(经典)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int connect_tcpserver(const char *ip, int port){
    int connfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in tcpserver_addr;
    memset(&tcpserver_addr, 0, sizeof (struct sockaddr_in));

    tcpserver_addr.sin_family = AF_INET;
    tcpserver_addr.sin_addr.s_addr = inet_addr(ip);
    tcpserver_addr.sin_port = htons(port);

    int ret = connect(connfd, (struct sockaddr*)&tcpserver_addr, sizeof(struct sockaddr_in));
    if(ret){
        perror("connect\n");
        return -1;
    }
    return connfd; 
}

send_recv_tcppkt()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define TEST_MESSAGE "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz\r\n"
int send_recv_tcppkt(int fd){
    char wbuffer[WBUFFER_LENGTH] = {0};
    int i = 0;
    //这里当tcp数据包过大时,大于协议栈的MTU时需要重新封装
    for(i = 0; i < 2; i++){
        strcpy(wbuffer + i*strlen(TEST_MESSAGE), TEST_MESSAGE);
    }
    int res = send(fd, wbuffer, strlen(wbuffer),0);
    if(res < 0){
        exit(1);
    }
    char rbuffer[RBUFFER_LENGTH] = {0};
    res = recv(fd, rbuffer, wbuffer, 0);
    if(res <= 0){
        exit(1);
    }
    if(strcmp(rbuffer,wbuffer) != 0){
        printf("failed: '%s' != '%s'\n", rbuffer, wbuffer);
        return -1;
    }
 }

测试结果

uring_tcp_server的结果。

uring

epoll_tcp_server的结果。

epoll

由于一次测试需150秒,故仅测了这一组数据,后续可自行进行测试。

本文由作者按照 CC BY 4.0 进行授权

热门标签