Linux异步管道多线程速率测试

目录

结论

源代码

main.c

utils.h

utils.c

Makefile

test.sh

文章链接


结论

Linux异步管道多线程速率测试_第1张图片

总体上说,由于是异步,多线程发包对单线程的处理不收很大影响,但是包的大小对发包速率影响较大,当宝大小在6500 byte时,发包速率最大,约为9000 Mbps。

下面直接给出源码

源代码

main.c

/**
 *	异步管道
 *	[email protected]
 *	2020年8月4日11:11:03
 */

#include 
#include 
#include 
#include 
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include 
#include 
#include 
#include 

#include "utils.h"

/* epoll最大event数 */
#define MAX_EVENTS 64

/* 管道两头的线程 */
static pthread_t tpipe_in1;
static pthread_t tpipe_in2;
static pthread_t tpipe_in3;
static pthread_t tpipe_in4;
static pthread_t tpipe_in5;
static pthread_t tpipe_out;

/* 管道两头的FD */
static int pipe_fd[2] = {-1};

/* 管道两头的打开方式 */
static FILE *pipe_in_fp = NULL;
static FILE *pipe_out_fp = NULL;

/* epoll fd */
static int epoll_fd = -1;

/* epoll events */
static struct epoll_event epoll_evs[MAX_EVENTS];

static volatile size_t pkg_size = 10;

FILE *record_rate_fp = NULL;

int nr_thread_write = 1;
int max_pkg_size = 10000;
int pkg_size_interval = 20;

/* 向管道发送数据,数据将从另一端输出 */
inline int mysendto(void *buf, size_t size) {
    int n = write(fileno(pipe_in_fp), buf, size);
//    printf("<< pipe << %s\n", buf);
}

/* 管道进口任务1 */
void * thread_pipe_in(void*arg) {

    char threadname[16];
    unsigned long int tid = pthread_self();
    pthread_getname_np(tid, threadname, 16);
    
	while(1) {
//		usleep(tid%521233);
        static char buf[1500] = {0};
//        sprintf(buf, "I'm thread %s-%lu.", threadname, tid);
        mysendto(buf, pkg_size);
	}
}

/* 管道出口任务主循环 */
int pipe_out_loop(void*arg) {

    static char buffer[4096] = {0};
    int nr_events = 0, iev;
    
    static long int npkg = 0;
    static long int nbyte = 0;
    static struct timeval timestart = {0,0};
    static struct timeval timeend = {0,0};
    
    static int start_flag = 0;
    
    nr_events = epoll_wait(epoll_fd, epoll_evs, MAX_EVENTS, -1);
    
    for(iev = 0; iev < nr_events; iev ++) {
        if(epoll_evs[iev].data.fd == fileno(pipe_out_fp) 
            && epoll_evs[iev].events&EPOLLIN) {
            
            int n = read(fileno(pipe_out_fp), buffer, 4096);
            if(start_flag == 0) {
                gettimeval(×tart);
            }
            start_flag = 1;
            npkg++;
            nbyte+=n;
//            printf(">> pipe >> %s\n", buffer);
            
        }
    }
    
    gettimeval(&timeend);

    if(npkg%100000==0) {
        static char description[256] = {0};
        static double Mbps = 0.0;
    
        sprintf(description, "PIPE PKG Size %4ld", pkg_size);
        Mbps = statistic_throughput(description, ×tart, &timeend, nbyte, npkg);

        fprintf(record_rate_fp, "%4ld        %10.2lf    \n", pkg_size, Mbps);
        fflush(record_rate_fp);
        
        memset(×tart, 0, sizeof(struct timeval));
        memset(&timeend, 0, sizeof(struct timeval));
        start_flag = 0;
        npkg = nbyte = 0;
        
        pkg_size += pkg_size_interval;

        if(pkg_size > max_pkg_size) {
            exit(1);
        }
    }
}

/* 管道出口任务 */
void * thread_pipe_out(void*arg) {
    
	while(1) {
        /* 该loop类比于fstack的ff_run(loop, NULL) */
        pipe_out_loop(NULL);
	}
}

/* 初始化管道 */
void pipe_initial() {

	pipe(pipe_fd);
    
	/* 打开管道两端 */
    pipe_in_fp = fdopen(pipe_fd[1], "w");
    pipe_out_fp = fdopen(pipe_fd[0], "r");

}

/* 启动任务 */
void thread_execute() {

    if(nr_thread_write>=1)
	pthread_create(&tpipe_in1, NULL, thread_pipe_in, NULL);
    if(nr_thread_write>=2)
	pthread_create(&tpipe_in2, NULL, thread_pipe_in, NULL);
    if(nr_thread_write>=3)
	pthread_create(&tpipe_in3, NULL, thread_pipe_in, NULL);
    if(nr_thread_write>=4)
	pthread_create(&tpipe_in4, NULL, thread_pipe_in, NULL);
    if(nr_thread_write>=5)
	pthread_create(&tpipe_in5, NULL, thread_pipe_in, NULL);

	pthread_create(&tpipe_out, NULL, thread_pipe_out, NULL);
    
    if(nr_thread_write>=1)
    pthread_setname_np(tpipe_in1, "pipe-in1");
    if(nr_thread_write>=2)
	pthread_setname_np(tpipe_in2, "pipe-in2");
    if(nr_thread_write>=3)
	pthread_setname_np(tpipe_in3, "pipe-in3");
    if(nr_thread_write>=4)
	pthread_setname_np(tpipe_in4, "pipe-in4");
    if(nr_thread_write>=5)
	pthread_setname_np(tpipe_in5, "pipe-in5");
    
	pthread_setname_np(tpipe_out, "pipe-out");
    
}

/* 主进程loop */
void main_loop() {

	while(1) {
		sleep(1);
        /* do nothing */
	}
}

/* 初始化epoll */
void epoll_initial() {
	epoll_fd = epoll_create(1);
	struct epoll_event pipe_ev;
	pipe_ev.data.fd = fileno(pipe_out_fp);
	pipe_ev.events = EPOLLIN;
	epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fileno(pipe_out_fp), &pipe_ev);
}

/* 主函数 */
int main (int argc, char *argv[]) {

    if(argc<5) {
        printf("%s [nthread] [max-pkg-size] [pkg-size-interval] [record-file-name] .\n", argv[0]);
        exit(1);
    
    } else {
        
        nr_thread_write = atoi(argv[1]);
        max_pkg_size = atoi(argv[2]);
        pkg_size_interval = atoi(argv[3]);
    }
    

    record_rate_fp = fopen(argv[4], "w");

	pipe_initial();/* 初始化管道 */
	
	epoll_initial();/* 初始化epoll */

	thread_execute();/* 开始执行任务 */

    main_loop();/*主循环,由主进程执行 */
}

 

utils.h

#ifndef __UTILS_H
#define __UTILS_H

#include 
#include 
#include 


/**
 *  打印log debug信息
 *  作者: 荣涛
 *  时间: s2020年7月15日10:12:24
 */
enum {
    __LV_INFO,
    __LV_WARNING,
    __LV_ERR,
    __LV_DEBUG,
};


#define log_info(fmt...) ___debug_log(__LV_INFO, __FILE__, __func__ ,__LINE__, fmt)
#define log_warn(fmt...) ___debug_log(__LV_WARNING, __FILE__, __func__ ,__LINE__, fmt)
#define log_error(fmt...) ___debug_log(__LV_ERR, __FILE__, __func__ ,__LINE__, fmt)
#define log_debg(fmt...) ___debug_log(__LV_DEBUG, __FILE__, __func__ ,__LINE__, fmt)


inline long int gettimeval(struct timeval *tv);

inline double statistic_throughput(char *description, 
            struct timeval *before, struct timeval *after, unsigned long int bytes, long int npkg);

inline int ___debug_log(int level, char *file, const char *func, int line, char *fmt, ...);


#endif

utils.c

#include "utils.h"


inline long int gettimeval(struct timeval *tv)
{
    gettimeofday(tv, NULL);    
}


inline double statistic_throughput(char *description, 
            struct timeval *before, struct timeval *after, unsigned long int bytes, long int npkg)
{
    double Mbps = 8*bytes*1.0/((after->tv_sec-before->tv_sec)*1000000.0+after->tv_usec-before->tv_usec);
    printf("-- %s: Total %.3lf Mbps, bytes = %ld(bits:%ld), npkg = %ld.\n", 
                            description?description:"Unknown Description", 
                            Mbps, bytes, bytes*8, npkg);
    return Mbps;
}



inline int ___debug_log(int level, char *file, const char *func, int line, char *fmt, ...)
{
    

    va_list av;
    va_start(av, fmt);

    switch(level) {
        case __LV_INFO:
            printf(" [%s INFO%s][%s:%s:%d]: ","\033[1;36m","\033[0m", basename(file), func, line);
            break;
        case __LV_WARNING:
            printf(" [%s WARN%s][%s:%s:%d]: ","\033[1;35m","\033[0m", basename(file), func, line);
            break;
        case __LV_ERR:
            printf("[%sERROR%s][%s:%s:%d]: ","\033[1;31m","\033[0m", basename(file), func, line);
            break;
        case __LV_DEBUG:
            printf("[%sDEBUG%s][%s:%s:%d]: ","\033[1m",   "\033[0m", basename(file), func, line);
            break;
    }
    
    int i = vprintf(fmt, av);

    va_end(av);

    return i;
}

 

Makefile

#编译

LIBS := -pthread -lrt

SOURCES := main.c utils.c

CC=gcc

TARGET = main

all: 
	$(CC) -o $(TARGET) $(SOURCES) $(LIBS)

clean:
	rm -rf $(TARGET)

 

test.sh

#!/bin/bash
# [email protected]

# ./main [nthread] [max-pkg-size] [pkg-size-interval] [record-file-name]

max_pkg_size=10000
pkg_size_interval=25


for it in  1 2 3 4 5
do
	./main $it $max_pkg_size $pkg_size_interval record-$it-$max_pkg_size-$pkg_size_interval.txt
done

文章链接

《Linux下实现多线程异步管道》https://rtoax.blog.csdn.net/article/details/107783941

你可能感兴趣的:(基础知识)