├── .gitignore ├── CMakeLists.txt ├── Makefile ├── README.md ├── config ├── arp.conf └── route.conf ├── dpdk_client.conf └── src ├── algorithm ├── algorithm.h ├── bitmap.h ├── gcd.h └── hashmap.h ├── common.h ├── main.cpp ├── main_mtcp.cpp └── rt_assert.h /.gitignore: -------------------------------------------------------------------------------- 1 | data 2 | build -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(most) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | add_compile_options(-O3 -Wall -g) 5 | add_compile_options(-mavx -msse4 -msse4.1 -msse4.2 -msse -msse2 -msse3) 6 | add_compile_options(-funroll-loops -fno-stack-protector -fwhole-program) 7 | add_compile_options(-fcse-skip-blocks -funsafe-loop-optimizations) 8 | set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++ -static-libgcc") 9 | 10 | add_executable(main src/main.cpp) 11 | target_link_libraries(main pthread) 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC=g++ -g -O3 -Wall -Werror 3 | DPDK=1 4 | CFLAGS=-DMAX_CPUS=1 -lm -lpthread 5 | 6 | # Add arch-specific optimization 7 | ifeq ($(shell uname -m),x86_64) 8 | LIBS += -m64 9 | endif 10 | 11 | # mtcp library and header 12 | MTCP_FLD =../mtcp/mtcp/ 13 | MTCP_INC =-I${MTCP_FLD}/include 14 | MTCP_LIB =-L${MTCP_FLD}/lib 15 | MTCP_TARGET = ${MTCP_LIB}/libmtcp.a 16 | 17 | UTIL_FLD = ../mtcp/util 18 | UTIL_INC = -I${UTIL_FLD}/include 19 | UTIL_OBJ = 20 | 21 | # util library and header 22 | INC = -I./include/ ${UTIL_INC} ${MTCP_INC} -I${UTIL_FLD}/include 23 | LIBS = ${MTCP_LIB} 24 | 25 | ifeq ($(DPDK),1) 26 | DPDK_MACHINE_LINKER_FLAGS=$${RTE_SDK}/$${RTE_TARGET}/lib/ldflags.txt 27 | DPDK_MACHINE_LDFLAGS=$(shell cat ${DPDK_MACHINE_LINKER_FLAGS}) 28 | LIBS += -g -O3 -pthread -lrt -march=native ${MTCP_FLD}/lib/libmtcp.a -lnuma -lmtcp -lpthread -lrt -ldl -lgmp -L${RTE_SDK}/${RTE_TARGET}/lib ${DPDK_MACHINE_LDFLAGS} 29 | endif 30 | 31 | 32 | ifeq ($V,) # no echo 33 | export MSG=@echo 34 | export HIDE=@ 35 | else 36 | export MSG=@\# 37 | export HIDE= 38 | endif 39 | 40 | 41 | all: build/main_mtcp 42 | 43 | build/main_mtcp.o: src/main_mtcp.cpp 44 | $(MSG) " CC $<" 45 | ${CC} -g -c $< -o $@ ${CFLAGS} ${INC} 46 | 47 | %: %.o 48 | $(MSG) " LD $<" 49 | ${CC} $< ${INC} ${UTIL_OBJ} -g -o $@ ${LIBS} 50 | 51 | clean: 52 | rm -f *~ build/main_mtcp build/main_mtcp.o log_* 53 | 54 | distclean: clean 55 | rm -rf Makefile 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # MOST的用户态TCP协议栈(DPDK)解法 3 | 4 | 这个分支是用户态协议栈的解法,算法相关的部分可以在master分支查看。 5 | 6 | 用户态协议栈相比内核协议栈大约能快几十微秒。 7 | 8 | ## 内核协议栈版本 9 | 10 | ``` 11 | mkdir build 12 | cd build 13 | cmake .. 14 | make 15 | ./main 16 | ``` 17 | 18 | ## 用户态协议栈(DPDK)版本 19 | 20 | 需要一块支持DPDK的网卡,我使用的是Intel E1G42ET双网口千兆网卡,使用82576芯片,淘宝价格135元。 21 | 22 | 首先需要编译[mTCP](https://github.com/mtcp-stack/mtcp),按照其中的指令完成: 23 | 24 | 1. 编译并安装dpdk 25 | 2. 安装驱动并且将网卡绑定到驱动上 26 | 3. 设置hugepages 27 | 4. 安装mTCP的内核模块,安装之后使用ifconfig能够看到一个名称为dpdk0的网卡 28 | 5. 使用sudo ifconfig dpdk0 192.168.1.108 netmask 255.255.255.0 up设置网卡的IP 29 | 6. 设置RTE_SDK和RTE_TARGET环境变量 30 | 7. 编译mTCP 31 | 32 | 坑: 33 | 1. mTCP可以将DPDK的网卡伪装成一块正常的网卡,这样就能够使用ifconfig进行IP配置。但是Ubuntu的图形化程序有时候会自动配置网卡,导致DPDK网卡的IP变成不是我们想要的。最好关闭网卡自动配置。 34 | 35 | 将mTCP目录和本目录放置在同一级父目录下,比如: 36 | 37 | ``` 38 | . 39 | ├── MOST 40 | └── mtcp 41 | ``` 42 | 43 | 然后在`MOST`目录下编译并运行程序: 44 | 45 | ``` 46 | mkdir build 47 | make 48 | sudo ./build/main_mtcp 49 | ``` 50 | -------------------------------------------------------------------------------- /config/arp.conf: -------------------------------------------------------------------------------- 1 | # This file is to configure static arp tables. 2 | # Rename this file to arp.conf and set the appropriate values. 3 | # Please save this file as config/arp.conf. Put the config/ 4 | # directory in the same directory where the binary lies. 5 | # 6 | # (Destination IP address/IP_prefix) (Destination MAC address) 7 | 8 | ARP_ENTRY 2 9 | 192.168.64.2/32 a0:36:9f:0f:bc:9d 10 | 192.168.1.80/32 00:d8:61:a8:60:8e 11 | -------------------------------------------------------------------------------- /config/route.conf: -------------------------------------------------------------------------------- 1 | # This file is routing table example of our testbed machine 2 | # Copy this file to route.conf and give appropriate routes 3 | # Please save this file as config/route.conf. Put the config/ 4 | # directory in the same directory where the binary lies. 5 | # 6 | # (Destination address)/(Prefix) (Device name) 7 | # 8 | # 9 | # Add entry for default gateway route as: 10 | # w.x.y.z/0 dpdk0 11 | # Always put the default gateway route as the last entry. 12 | # Make sure that the mask (Prefix) is set to 0. For example, 13 | # if the default gateway IP address is 10.0.0.10, then the 14 | # entry will be: 15 | # 10.0.0.10/0 dpdk0 16 | # 17 | 18 | ROUTES 1 19 | 192.168.1.80/0 dpdk0 20 | -------------------------------------------------------------------------------- /dpdk_client.conf: -------------------------------------------------------------------------------- 1 | ############### mtcp configuration file ############### 2 | 3 | # The underlying I/O module you want to use. Please 4 | # enable only one out of the two. 5 | #io = psio 6 | io = dpdk 7 | 8 | # No. of cores setting (enabling this option will override 9 | # the `cpu' config for those applications that accept 10 | # num_cores as command line arguments) 11 | # 12 | # e.g. in case ./epwget is executed with `-N 4', the 13 | # mtcp core will still invoke 8 mTCP threads if the 14 | # following line is uncommented. 15 | #num_cores = 8 16 | 17 | # Number of memory channels per processor socket (dpdk-only) 18 | num_mem_ch = 1 19 | 20 | # Used port (please adjust accordingly) 21 | #------ PSIO ports -------# 22 | #port = xge0 xge1 23 | #port = xge 24 | #------ DPDK ports -------# 25 | port = dpdk0 26 | #port = dpdk0:0 27 | #port = dpdk0:1 28 | 29 | # Enable multi-process support (under development) 30 | #multiprocess = 0 master 31 | #multiprocess = 1 32 | 33 | # Congestion control algorithm 34 | # (only available when configured with --enable-ccp) 35 | # cc = reno 36 | # cc = cubic 37 | 38 | # Receive buffer size of sockets 39 | rcvbuf = 524288 40 | #rcvbuf = 16384 41 | 42 | # Send buffer size of sockets 43 | #sndbuf = 2048 44 | sndbuf = 524288 45 | #sndbuf = 41943040 46 | #sndbuf = 146000 47 | 48 | # Maximum concurrency per core 49 | max_concurrency = 100 50 | 51 | # Maximum number of socket buffers per core 52 | # Set this to small value if there are many idle connections 53 | max_num_buffers = 100 54 | 55 | # TCO timeout seconds 56 | # (tcp_timeout = -1 can disable the timeout check) 57 | tcp_timeout = 30 58 | 59 | # TCP timewait seconds 60 | tcp_timewait = 0 61 | 62 | # Interface to print stats (please adjust accordingly) 63 | # You can enable multiple ports in a line 64 | #------ PSIO ports -------# 65 | #stat_print = xge0 66 | #stat_print = xge1 67 | #------ DPDK ports -------# 68 | #stat_print = dpdk0 69 | #stat_print = p2p1 70 | #stat_print = 10gp1 71 | 72 | ####################################################### 73 | -------------------------------------------------------------------------------- /src/algorithm/algorithm.h: -------------------------------------------------------------------------------- 1 | #ifndef __ALGORITHM_H__ 2 | #define __ALGORITHM_H__ 3 | 4 | #include "gcd.h" 5 | #include "../rt_assert.h" 6 | 7 | #define MAXPOW 1024 8 | 9 | template 10 | T fast_multiply(T a, T b, T M) 11 | { 12 | if (b == 0) return 0; 13 | T ans = fast_multiply(a, b/2, M); 14 | ans = (ans + ans) % M; 15 | if (b & 1) 16 | { 17 | ans = (ans + a) % M; 18 | } 19 | return ans; 20 | } 21 | 22 | template 23 | class Algorithm 24 | { 25 | T __attribute__((aligned(64))) M, prefix; 26 | T __attribute__((aligned(64))) pow10[MAXPOW]; 27 | T __attribute__((aligned(64))) inv10[MAXPOW]; 28 | 29 | MAP_T map; 30 | 31 | public: 32 | Algorithm(const char* Ms) 33 | { 34 | M = 0; 35 | for (int i = 0; Ms[i]; i ++) 36 | { 37 | M = M * 10 + Ms[i] - '0'; 38 | } 39 | 40 | pow10[0] = 1; 41 | for (int i = 1; i < MAXPOW; i ++) 42 | { 43 | pow10[i] = (pow10[i-1] * 10) % M; 44 | } 45 | for (int i = 0; i < MAXPOW; i ++) 46 | { 47 | inv10[i] = inv(pow10[i], M); 48 | 49 | rt_assert(fast_multiply(pow10[i], inv10[i], M) == 1); 50 | } 51 | } 52 | 53 | inline void init(int end, const char* data) 54 | { 55 | map.init(); 56 | 57 | prefix = 0; 58 | for (int i = N; i >= 1; i --) 59 | { 60 | if (data[end - i] == '0') continue; 61 | map.set(prefix, end-i); 62 | prefix = (prefix + (data[end - i] - '0') * inv10[N-i]) % M; 63 | } 64 | } 65 | 66 | inline void update_prefix(int pos, int len, char ch) 67 | { 68 | map.set(prefix, pos); 69 | prefix = (prefix + (ch - '0') * inv10[len]) % M; 70 | } 71 | 72 | inline int find() 73 | { 74 | return map.find(prefix); 75 | } 76 | }; 77 | 78 | #endif // __ALGORITHM_H__ 79 | -------------------------------------------------------------------------------- /src/algorithm/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef __BITMAP_H__ 2 | #define __BITMAP_H__ 3 | 4 | #include 5 | 6 | template 7 | class BitMap 8 | { 9 | const int BITMAP_WIDTH = 8; 10 | uint8_t __attribute__((aligned(64))) bitmap[BITMAP_SIZE]; 11 | KEY_T __attribute__((aligned(64))) keys[1024]; 12 | int __attribute__((aligned(64))) values[1024]; 13 | int size; 14 | public: 15 | 16 | inline void init() 17 | { 18 | memset(bitmap, 0, sizeof(bitmap)); 19 | size = 0; 20 | } 21 | 22 | inline void set(const KEY_T key, int value) 23 | { 24 | int pos = key % (BITMAP_SIZE * BITMAP_WIDTH); 25 | bitmap[pos / BITMAP_WIDTH] |= 1 << (pos % BITMAP_WIDTH); 26 | keys[size] = key; 27 | values[size] = value; 28 | size++; 29 | } 30 | 31 | inline int find(const KEY_T key) 32 | { 33 | int pos = key % (BITMAP_SIZE * BITMAP_WIDTH); 34 | 35 | if ((bitmap[pos / BITMAP_WIDTH] >> (pos % BITMAP_WIDTH)) & 1) 36 | { 37 | for (int i = 0; i < size; i ++) 38 | { 39 | if (keys[i] == key) 40 | { 41 | return values[i]; 42 | } 43 | } 44 | } 45 | return 0; 46 | } 47 | }; 48 | 49 | #endif // __BITMAP_H__ 50 | -------------------------------------------------------------------------------- /src/algorithm/gcd.h: -------------------------------------------------------------------------------- 1 | #ifndef __GCD_H__ 2 | #define __GCD_H__ 3 | 4 | #include "../rt_assert.h" 5 | 6 | // solve a*x + b*y = g 7 | template 8 | void exgcd(T a, T b, T &g, T &x, T &y) 9 | { 10 | if (b == 0) 11 | { 12 | g = a; 13 | x = 1; 14 | y = 0; 15 | } 16 | else 17 | { 18 | exgcd(b, a % b, g, y, x); 19 | y -= a / b * x; 20 | } 21 | } 22 | 23 | // inv(x) * x % M = 1 24 | template 25 | T inv(T x, T M) 26 | { 27 | T y, k, g; 28 | exgcd(x, M, g, y, k); 29 | rt_assert(g == 1); 30 | return ((y % M) + M) % M; 31 | } 32 | 33 | #endif // __GCD_H__ 34 | -------------------------------------------------------------------------------- /src/algorithm/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASHMAP_H__ 2 | #define __HASHMAP_H__ 3 | 4 | // 4194304 5 | 6 | template 7 | class HashMap 8 | { 9 | int hash_idx[HASHMAP_SIZE]; 10 | public: 11 | 12 | inline void init() 13 | { 14 | memset(hash_idx, 0, sizeof(hash_idx)); 15 | } 16 | 17 | inline void set(const KEY_T key, int value) 18 | { 19 | hash_idx[key % HASHMAP_SIZE] = value; 20 | } 21 | 22 | inline int find(const KEY_T key) 23 | { 24 | return hash_idx[key % HASHMAP_SIZE]; 25 | } 26 | }; 27 | 28 | #endif // __HASHMAP_H__ 29 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H__ 2 | #define __COMMON_H__ 3 | 4 | #include "rt_assert.h" 5 | 6 | #define MOST_N 256 7 | #define MOST_M1_STR "59937251" 8 | #define MOST_M2_STR "104648257118348370704723401" 9 | #define MOST_M3_STR "500000000000000221" 10 | #define MOST_M4_STR "79792266297612001" 11 | 12 | #define SERVER_ADDR "192.168.1.80" 13 | 14 | #define N_INPUT_SOCKET 8 15 | 16 | static inline void bind_cpu(int core) 17 | { 18 | cpu_set_t mask; 19 | CPU_ZERO(&mask); 20 | CPU_SET(core, &mask); 21 | rt_assert_eq(pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask), 0); 22 | } 23 | 24 | // 获取当前时间,单位:秒 25 | static inline double get_timestamp() 26 | { 27 | timespec ts; 28 | clock_gettime(CLOCK_REALTIME, &ts); 29 | return ts.tv_sec + ts.tv_nsec / 1e9; 30 | } 31 | 32 | #endif // __COMMON_H__ 33 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | #include "rt_assert.h" 18 | #include "algorithm/algorithm.h" 19 | #include "algorithm/hashmap.h" 20 | #include "algorithm/bitmap.h" 21 | 22 | using namespace std; 23 | 24 | Algorithm> alg_m1(MOST_M1_STR); 25 | Algorithm<__int128_t, MOST_N, HashMap<__int128_t, 33554432>> alg_m2(MOST_M2_STR); 26 | Algorithm> alg_m3(MOST_M3_STR); 27 | Algorithm> alg_m4(MOST_M4_STR); 28 | 29 | // Algorithm> alg_m1(MOST_M1_STR); 30 | // Algorithm<__int128_t, MOST_N, BitMap<__int128_t, 1024>> alg_m2(MOST_M2_STR); 31 | // Algorithm> alg_m3(MOST_M3_STR); 32 | // Algorithm> alg_m4(MOST_M4_STR); 33 | 34 | // 不同长度的http头 35 | char __attribute__((aligned(64))) headers[128][1024 * 10]; 36 | int __attribute__((aligned(64))) headers_n[128]; 37 | 38 | char __attribute__((aligned(64))) buffer[1024 * 1024 * 256]; 39 | atomic buffer_size; 40 | atomic received_time; 41 | 42 | int connect_input() 43 | { 44 | int socket_fd = socket(AF_INET, SOCK_STREAM, 0); 45 | printf("input socket_fd = %d\n", socket_fd); 46 | 47 | // connect 48 | { 49 | struct sockaddr_storage addr; 50 | memset(&addr, 0, sizeof(addr)); 51 | 52 | struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&addr; 53 | addr_v4->sin_family = AF_INET; 54 | addr_v4->sin_port = htons(10001); 55 | 56 | rt_assert_eq(inet_pton(AF_INET, SERVER_ADDR, &addr_v4->sin_addr), 1); 57 | rt_assert_eq(connect(socket_fd, (struct sockaddr *)addr_v4, sizeof(*addr_v4)), 0); 58 | 59 | printf("connect success\n"); 60 | } 61 | 62 | // skip http header 63 | { 64 | char tmp[1024]; 65 | while (true) 66 | { 67 | memset(tmp, 0, sizeof(tmp)); 68 | ssize_t n = read(socket_fd, tmp, sizeof(tmp)); 69 | rt_assert(n > 0); 70 | if (strstr(tmp, "\r\n\r\n")) 71 | break; 72 | } 73 | printf("skip http header success\n"); 74 | } 75 | 76 | rt_assert_eq(fcntl(socket_fd, F_SETFL, fcntl(socket_fd, F_GETFL) | O_NONBLOCK), 0); 77 | 78 | return socket_fd; 79 | } 80 | 81 | int connect_post() 82 | { 83 | int socket_fd = socket(AF_INET, SOCK_STREAM, 0); 84 | rt_assert(socket_fd >= 0); 85 | 86 | // no delay 87 | { 88 | int flag = 1; 89 | int result = setsockopt(socket_fd, /* socket affected */ 90 | IPPROTO_TCP, /* set option at TCP level */ 91 | TCP_NODELAY, /* name of option */ 92 | (char *)&flag, /* the cast is historical cruft */ 93 | sizeof(int)); /* length of option value */ 94 | rt_assert_eq(result, 0); 95 | } 96 | 97 | // connect 98 | { 99 | struct sockaddr_storage addr; 100 | memset(&addr, 0, sizeof(addr)); 101 | 102 | struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&addr; 103 | addr_v4->sin_family = AF_INET; 104 | addr_v4->sin_port = htons(10002); 105 | 106 | rt_assert_eq(inet_pton(AF_INET, SERVER_ADDR, &addr_v4->sin_addr), 1); 107 | 108 | rt_assert_eq(connect(socket_fd, (struct sockaddr *)addr_v4, sizeof(*addr_v4)), 0); 109 | } 110 | 111 | rt_assert_eq(fcntl(socket_fd, F_SETFL, fcntl(socket_fd, F_GETFL) | O_NONBLOCK), 0); 112 | 113 | headers_n[socket_fd] = sprintf(headers[socket_fd], "POST /submit HTTP/1.1\r\n"); 114 | return socket_fd; 115 | } 116 | 117 | void submit(int submit_fd, int begin, int end) 118 | { 119 | int len = end - begin; 120 | int size = headers_n[submit_fd]; 121 | size += sprintf(headers[submit_fd] + size, "Content-Length: %d\r\n\r\n", len); 122 | memcpy(headers[submit_fd] + size, buffer + begin, len); 123 | int n = write(submit_fd, headers[submit_fd], size + len); 124 | rt_assert_eq(n, size + len); 125 | } 126 | 127 | template 128 | void run_alg(int cpu, const char *flag, ALG &alg) 129 | { 130 | bind_cpu(cpu); 131 | 132 | int submit_fd = connect_post(); 133 | while (buffer_size.load() < MOST_N) 134 | ; 135 | 136 | double __attribute__((aligned(64))) send_times[1024]; 137 | int __attribute__((aligned(64))) send_begin[1024]; 138 | int __attribute__((aligned(64))) send_end[1024]; 139 | int send_times_N; 140 | 141 | int L = buffer_size.load(); 142 | while (true) 143 | { 144 | alg.init(L, buffer); 145 | while (buffer_size.load() == L) 146 | ; 147 | int R = buffer_size.load(); 148 | send_times_N = 0; 149 | 150 | for (int k = L; k < R; k++) 151 | { 152 | if (buffer[k] != '0') 153 | { 154 | alg.update_prefix(k, (k - L) + MOST_N, buffer[k]); 155 | } 156 | int begin = alg.find(); 157 | if (begin > 0) 158 | { 159 | send_times[send_times_N] = get_timestamp(); 160 | send_begin[send_times_N] = begin; 161 | send_end[send_times_N] = k + 1; 162 | send_times_N++; 163 | submit(submit_fd, begin, k + 1); 164 | } 165 | } 166 | L = R; 167 | 168 | for (int i = 0; i < send_times_N; i++) 169 | { 170 | printf("submit %s %.6lf %s\n", flag, send_times[i] - received_time.load(), std::string(buffer + send_begin[i], send_end[i] - send_begin[i]).c_str()); 171 | } 172 | { 173 | char buf[1024]; 174 | while (true) 175 | { 176 | int n = read(submit_fd, buf, sizeof(buf)); 177 | rt_assert(n > 0 || errno == EAGAIN); 178 | if (n <= 0) 179 | break; 180 | } 181 | } 182 | } 183 | } 184 | 185 | int main() 186 | { 187 | int __attribute__((aligned(64))) input_sockets[N_INPUT_SOCKET]; 188 | int __attribute__((aligned(64))) input_sockets_pos[N_INPUT_SOCKET]; 189 | for (int i = 0; i < N_INPUT_SOCKET; i++) 190 | { 191 | input_sockets[i] = connect_input(); 192 | input_sockets_pos[i] = 0; 193 | } 194 | buffer_size.store(0); 195 | 196 | thread tm2([&]() 197 | { run_alg(1, "M2", alg_m2); }); 198 | thread tm3([&]() 199 | { run_alg(8, "M3", alg_m3); }); 200 | thread tm4([&]() 201 | { run_alg(9, "M4", alg_m4); }); 202 | 203 | bind_cpu(0); 204 | int submit_fd = connect_post(); 205 | 206 | { // sync sockets 207 | double last_recv_time = -1; 208 | while (true) 209 | { 210 | char buf[1024]; 211 | for (int i = 0; i < N_INPUT_SOCKET; i++) 212 | { 213 | int n = read(input_sockets[i], buf, sizeof(buf)); 214 | rt_assert(n > 0 || errno == EAGAIN); 215 | if (n > 0) 216 | { 217 | last_recv_time = get_timestamp(); 218 | } 219 | } 220 | 221 | if (last_recv_time > 0 && last_recv_time + 0.7 < get_timestamp()) 222 | { 223 | break; 224 | } 225 | } 226 | printf("sync sockets done!\n"); 227 | } 228 | 229 | while (buffer_size.load() < MOST_N) 230 | { 231 | for (int i = 0; i < N_INPUT_SOCKET; i++) 232 | { 233 | int n = read(input_sockets[i], buffer + input_sockets_pos[i], 1024); 234 | rt_assert(n > 0 || errno == EAGAIN); 235 | 236 | if (n > 0) 237 | { 238 | input_sockets_pos[i] += n; 239 | buffer_size.store(max(buffer_size.load(), input_sockets_pos[i])); 240 | } 241 | } 242 | } 243 | 244 | alg_m1.init(buffer_size.load(), buffer); 245 | double __attribute__((aligned(64))) send_times[1024]; 246 | int __attribute__((aligned(64))) send_begin[1024]; 247 | int __attribute__((aligned(64))) send_end[1024]; 248 | int send_times_N; 249 | while (true) 250 | { 251 | for (int i = 0; i < N_INPUT_SOCKET; i++) 252 | { 253 | int n = read(input_sockets[i], buffer + input_sockets_pos[i], 1024); 254 | rt_assert(n > 0 || errno == EAGAIN); 255 | 256 | if (n > 0) 257 | { 258 | send_times_N = 0; 259 | received_time.store(get_timestamp()); 260 | input_sockets_pos[i] += n; 261 | 262 | if (input_sockets_pos[i] > buffer_size.load()) 263 | { 264 | int L = buffer_size.load(); 265 | int R = input_sockets_pos[i]; 266 | buffer_size.store(R); 267 | 268 | for (int k = L; k < R; k++) 269 | { 270 | if (buffer[k] != '0') 271 | { 272 | alg_m1.update_prefix(k, (k - L) + MOST_N, buffer[k]); 273 | } 274 | if ((buffer[k] - '0') % 2 == 0) 275 | { 276 | int begin = alg_m1.find(); 277 | if (begin > 0) 278 | { 279 | send_times[send_times_N] = get_timestamp(); 280 | send_begin[send_times_N] = begin; 281 | send_end[send_times_N] = k + 1; 282 | send_times_N++; 283 | submit(submit_fd, begin, k + 1); 284 | } 285 | } 286 | } 287 | 288 | alg_m1.init(buffer_size.load(), buffer); 289 | } 290 | 291 | for (int i = 0; i < send_times_N; i++) 292 | { 293 | printf("submit M1 %.6lf %s\n", send_times[i] - received_time.load(), std::string(buffer + send_begin[i], send_end[i] - send_begin[i]).c_str()); 294 | } 295 | { 296 | char buf[1024]; 297 | while (true) 298 | { 299 | int n = read(submit_fd, buf, sizeof(buf)); 300 | rt_assert(n > 0 || errno == EAGAIN); 301 | if (n <= 0) 302 | break; 303 | } 304 | } 305 | 306 | fflush(stdout); 307 | } 308 | } 309 | } 310 | 311 | return 0; 312 | } 313 | -------------------------------------------------------------------------------- /src/main_mtcp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | #include "common.h" 43 | #include "algorithm/algorithm.h" 44 | #include "algorithm/hashmap.h" 45 | #include "algorithm/bitmap.h" 46 | 47 | using namespace std; 48 | 49 | // runtime assert, this assert cannot be disabled by compile flags 50 | #define mtcp_assert(expr) \ 51 | { \ 52 | bool passed = (expr); \ 53 | if (!passed) \ 54 | { \ 55 | fprintf(stderr, "Error: mtcp_assert failed at %s:%d, expr = `%s`, errno = %s\n", __FILE__, __LINE__, #expr, strerror(errno)); \ 56 | mtcp_exit(); \ 57 | } \ 58 | } 59 | 60 | #define mtcp_assert_eq(a, b) mtcp_assert((a) == (b)); 61 | 62 | Algorithm> alg_m1(MOST_M1_STR); 63 | Algorithm<__int128_t, MOST_N, HashMap<__int128_t, 33554432>> alg_m2(MOST_M2_STR); 64 | Algorithm> alg_m3(MOST_M3_STR); 65 | Algorithm> alg_m4(MOST_M4_STR); 66 | 67 | // Algorithm> alg_m1(MOST_M1_STR); 68 | // Algorithm<__int128_t, MOST_N, BitMap<__int128_t, 1024>> alg_m2(MOST_M2_STR); 69 | // Algorithm> alg_m3(MOST_M3_STR); 70 | // Algorithm> alg_m4(MOST_M4_STR); 71 | 72 | // 不同长度的http头 73 | char __attribute__((aligned(64))) headers[128][1024 * 10]; 74 | int __attribute__((aligned(64))) headers_n[128]; 75 | 76 | char __attribute__((aligned(64))) buffer[1024 * 1024 * 256]; 77 | atomic finished_cnt; 78 | atomic buffer_size; 79 | atomic received_time; 80 | 81 | mctx_t mctx = 0; 82 | vector all_sockets; 83 | 84 | queue possible_ports; 85 | std::mutex possible_ports_mtx; 86 | 87 | void mtcp_exit() 88 | { 89 | if (mctx) 90 | { 91 | for (int s : all_sockets) 92 | { 93 | mtcp_close(mctx, s); 94 | } 95 | sleep(1); 96 | } 97 | exit(-1); 98 | } 99 | 100 | void SignalHandler(int signum) 101 | { 102 | mtcp_exit(); 103 | } 104 | 105 | int connect_input() 106 | { 107 | int socket_fd = mtcp_socket(mctx, AF_INET, SOCK_STREAM, 0); 108 | printf("input socket_fd = %d\n", socket_fd); 109 | all_sockets.push_back(socket_fd); 110 | 111 | int port; 112 | { 113 | std::lock_guard lock(possible_ports_mtx); 114 | port = possible_ports.front(); 115 | possible_ports.pop(); 116 | } 117 | { 118 | struct sockaddr_in addr; 119 | 120 | bzero(&addr, sizeof(struct sockaddr_in)); 121 | addr.sin_family = AF_INET; 122 | mtcp_assert(inet_pton(AF_INET, "192.168.1.108", &addr.sin_addr) == 1); 123 | addr.sin_port = htons(port); 124 | 125 | mtcp_assert(mtcp_bind(mctx, socket_fd, (const sockaddr *)&addr, sizeof(addr)) == 0); 126 | } 127 | 128 | mtcp_setsock_nonblock(mctx, socket_fd); 129 | 130 | // connect 131 | { 132 | struct sockaddr_storage addr; 133 | memset(&addr, 0, sizeof(addr)); 134 | 135 | struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&addr; 136 | addr_v4->sin_family = AF_INET; 137 | addr_v4->sin_port = htons(10001); 138 | 139 | mtcp_assert(inet_pton(AF_INET, SERVER_ADDR, &addr_v4->sin_addr) == 1); 140 | mtcp_connect(mctx, socket_fd, (struct sockaddr *)addr_v4, sizeof(*addr_v4)); 141 | 142 | printf("connect success\n"); 143 | } 144 | 145 | // skip http header 146 | { 147 | char tmp[1024]; 148 | while (true) 149 | { 150 | memset(tmp, 0, sizeof(tmp)); 151 | errno = 0; 152 | ssize_t n = mtcp_read(mctx, socket_fd, tmp, sizeof(tmp)); 153 | if (n < 0 && errno == EAGAIN) 154 | continue; 155 | if (strstr(tmp, "\r\n\r\n")) 156 | break; 157 | } 158 | printf("skip http header success\n"); 159 | } 160 | 161 | return socket_fd; 162 | } 163 | 164 | int connect_post() 165 | { 166 | int socket_fd = mtcp_socket(mctx, AF_INET, SOCK_STREAM, 0); 167 | mtcp_assert(socket_fd >= 0); 168 | all_sockets.push_back(socket_fd); 169 | 170 | int port; 171 | { 172 | std::lock_guard lock(possible_ports_mtx); 173 | port = possible_ports.front(); 174 | possible_ports.pop(); 175 | } 176 | { 177 | struct sockaddr_in addr; 178 | 179 | bzero(&addr, sizeof(struct sockaddr_in)); 180 | addr.sin_family = AF_INET; 181 | mtcp_assert(inet_pton(AF_INET, "192.168.1.108", &addr.sin_addr) == 1); 182 | addr.sin_port = htons(port); 183 | 184 | mtcp_assert(mtcp_bind(mctx, socket_fd, (const sockaddr *)&addr, sizeof(addr)) == 0); 185 | } 186 | 187 | // no delay 188 | { 189 | int flag = 1; 190 | int result = mtcp_setsockopt(mctx, socket_fd, /* socket affected */ 191 | IPPROTO_TCP, /* set option at TCP level */ 192 | TCP_NODELAY, /* name of option */ 193 | (char *)&flag, /* the cast is historical cruft */ 194 | sizeof(int)); /* length of option value */ 195 | mtcp_assert_eq(result, 0); 196 | } 197 | 198 | // connect 199 | { 200 | struct sockaddr_storage addr; 201 | memset(&addr, 0, sizeof(addr)); 202 | 203 | struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&addr; 204 | addr_v4->sin_family = AF_INET; 205 | addr_v4->sin_port = htons(10002); 206 | 207 | mtcp_assert_eq(inet_pton(AF_INET, SERVER_ADDR, &addr_v4->sin_addr), 1); 208 | 209 | mtcp_assert_eq(mtcp_connect(mctx, socket_fd, (struct sockaddr *)addr_v4, sizeof(*addr_v4)), 0); 210 | } 211 | 212 | mtcp_setsock_nonblock(mctx, socket_fd); 213 | 214 | headers_n[socket_fd] = sprintf(headers[socket_fd], "POST /submit HTTP/1.1\r\n"); 215 | return socket_fd; 216 | } 217 | 218 | void submit(int submit_fd, int begin, int end) 219 | { 220 | int len = end - begin; 221 | int size = headers_n[submit_fd]; 222 | size += sprintf(headers[submit_fd] + size, "Content-Length: %d\r\n\r\n", len); 223 | memcpy(headers[submit_fd] + size, buffer + begin, len); 224 | int n = mtcp_write(mctx, submit_fd, headers[submit_fd], size + len); 225 | mtcp_assert_eq(n, size + len); 226 | } 227 | 228 | template 229 | void run_alg(int cpu, const char *flag, ALG &alg) 230 | { 231 | bind_cpu(cpu); 232 | 233 | int submit_fd = connect_post(); 234 | while (buffer_size.load() < MOST_N) 235 | ; 236 | 237 | double __attribute__((aligned(64))) send_times[1024]; 238 | int __attribute__((aligned(64))) send_begin[1024]; 239 | int __attribute__((aligned(64))) send_end[1024]; 240 | int send_times_N; 241 | 242 | int L = buffer_size.load(); 243 | while (true) 244 | { 245 | alg.init(L, buffer); 246 | while (buffer_size.load() == L) 247 | ; 248 | double rtime = received_time.load(); 249 | int R = buffer_size.load(); 250 | send_times_N = 0; 251 | 252 | for (int k = L; k < R; k++) 253 | { 254 | if (buffer[k] != '0') 255 | { 256 | alg.update_prefix(k, (k - L) + MOST_N, buffer[k]); 257 | } 258 | int begin = alg.find(); 259 | if (begin > 0) 260 | { 261 | submit(submit_fd, begin, k + 1); 262 | 263 | send_times[send_times_N] = get_timestamp(); 264 | send_begin[send_times_N] = begin; 265 | send_end[send_times_N] = k + 1; 266 | send_times_N++; 267 | } 268 | } 269 | L = R; 270 | 271 | finished_cnt.fetch_add(1); 272 | while (finished_cnt.load() < 4) 273 | ; 274 | 275 | for (int i = 0; i < send_times_N; i++) 276 | { 277 | printf("submit %s %.6lf %s\n", flag, send_times[i] - rtime, std::string(buffer + send_begin[i], send_end[i] - send_begin[i]).c_str()); 278 | } 279 | { 280 | char buf[1024]; 281 | while (true) 282 | { 283 | int n = mtcp_read(mctx, submit_fd, buf, sizeof(buf)); 284 | mtcp_assert(n > 0 || errno == EAGAIN); 285 | if (n <= 0) 286 | break; 287 | } 288 | } 289 | } 290 | } 291 | 292 | int main() 293 | { 294 | // Seed RNG 295 | srand(time(NULL)); 296 | 297 | { 298 | set ports; 299 | for (int i = 0; i < 1000; i++) 300 | { 301 | int port; 302 | while (true) 303 | { 304 | port = rand() % 10000 + 1025; 305 | if (ports.find(port) == ports.end()) 306 | break; 307 | } 308 | ports.insert(port); 309 | possible_ports.push(port); 310 | } 311 | } 312 | 313 | struct mtcp_conf mcfg; 314 | 315 | mtcp_getconf(&mcfg); 316 | mcfg.num_cores = 1; 317 | mtcp_setconf(&mcfg); 318 | 319 | if (mtcp_init("dpdk_client.conf")) 320 | { 321 | mtcp_assert(false); 322 | return -1; 323 | } 324 | 325 | mtcp_getconf(&mcfg); 326 | mcfg.max_concurrency = 32; 327 | mcfg.max_num_buffers = 32; 328 | mtcp_setconf(&mcfg); 329 | 330 | mtcp_register_signal(SIGINT, SignalHandler); 331 | 332 | mctx = mtcp_create_context(0); 333 | { 334 | struct sockaddr_in daddr; 335 | daddr.sin_family = AF_INET; 336 | daddr.sin_addr.s_addr = inet_addr("192.168.1.80"); 337 | daddr.sin_port = htons(2047); 338 | mtcp_init_rss(mctx, INADDR_ANY, 1, daddr.sin_addr.s_addr, daddr.sin_port); 339 | } 340 | 341 | int __attribute__((aligned(64))) input_sockets[N_INPUT_SOCKET]; 342 | int __attribute__((aligned(64))) input_sockets_pos[N_INPUT_SOCKET]; 343 | for (int i = 0; i < N_INPUT_SOCKET; i++) 344 | { 345 | input_sockets[i] = connect_input(); 346 | input_sockets_pos[i] = 0; 347 | } 348 | buffer_size.store(0); 349 | 350 | thread tm2([&]() 351 | { run_alg(2, "M2", alg_m2); }); 352 | thread tm3([&]() 353 | { run_alg(8, "M3", alg_m3); }); 354 | thread tm4([&]() 355 | { run_alg(9, "M4", alg_m4); }); 356 | 357 | bind_cpu(1); 358 | int submit_fd = connect_post(); 359 | 360 | { // sync sockets 361 | double last_recv_time = -1; 362 | while (true) 363 | { 364 | char buf[1024]; 365 | for (int i = 0; i < N_INPUT_SOCKET; i++) 366 | { 367 | int n = mtcp_read(mctx, input_sockets[i], buf, sizeof(buf)); 368 | mtcp_assert(n > 0 || errno == EAGAIN); 369 | if (n > 0) 370 | { 371 | last_recv_time = get_timestamp(); 372 | } 373 | } 374 | 375 | if (last_recv_time > 0 && last_recv_time + 0.7 < get_timestamp()) 376 | { 377 | break; 378 | } 379 | } 380 | printf("sync sockets done!\n"); 381 | } 382 | 383 | while (buffer_size.load() < MOST_N) 384 | { 385 | for (int i = 0; i < N_INPUT_SOCKET; i++) 386 | { 387 | int n = mtcp_read(mctx, input_sockets[i], buffer + input_sockets_pos[i], 1024); 388 | mtcp_assert(n > 0 || errno == EAGAIN); 389 | 390 | if (n > 0) 391 | { 392 | input_sockets_pos[i] += n; 393 | buffer_size.store(max(buffer_size.load(), input_sockets_pos[i])); 394 | } 395 | } 396 | } 397 | 398 | alg_m1.init(buffer_size.load(), buffer); 399 | double __attribute__((aligned(64))) send_times[1024]; 400 | int __attribute__((aligned(64))) send_begin[1024]; 401 | int __attribute__((aligned(64))) send_end[1024]; 402 | int send_times_N; 403 | while (true) 404 | { 405 | for (int i = 0; i < N_INPUT_SOCKET; i++) 406 | { 407 | received_time.store(get_timestamp()); 408 | int n = mtcp_read(mctx, input_sockets[i], buffer + input_sockets_pos[i], 1024); 409 | mtcp_assert(n > 0 || errno == EAGAIN); 410 | 411 | if (n > 0) 412 | { 413 | send_times_N = 0; 414 | input_sockets_pos[i] += n; 415 | 416 | if (input_sockets_pos[i] > buffer_size.load()) 417 | { 418 | int L = buffer_size.load(); 419 | int R = input_sockets_pos[i]; 420 | finished_cnt.store(0); 421 | buffer_size.store(R); 422 | 423 | for (int k = L; k < R; k++) 424 | { 425 | if (buffer[k] != '0') 426 | { 427 | alg_m1.update_prefix(k, (k - L) + MOST_N, buffer[k]); 428 | } 429 | if ((buffer[k] - '0') % 2 == 0) 430 | { 431 | int begin = alg_m1.find(); 432 | if (begin > 0) 433 | { 434 | submit(submit_fd, begin, k + 1); 435 | 436 | send_times[send_times_N] = get_timestamp(); 437 | send_begin[send_times_N] = begin; 438 | send_end[send_times_N] = k + 1; 439 | send_times_N++; 440 | } 441 | } 442 | } 443 | 444 | alg_m1.init(buffer_size.load(), buffer); 445 | finished_cnt.fetch_add(1); 446 | while (finished_cnt.load() < 4) 447 | ; 448 | } 449 | 450 | for (int i = 0; i < send_times_N; i++) 451 | { 452 | printf("submit M1 %.6lf %s\n", send_times[i] - received_time.load(), std::string(buffer + send_begin[i], send_end[i] - send_begin[i]).c_str()); 453 | } 454 | { 455 | char buf[1024]; 456 | while (true) 457 | { 458 | int n = mtcp_read(mctx, submit_fd, buf, sizeof(buf)); 459 | mtcp_assert(n > 0 || errno == EAGAIN); 460 | if (n <= 0) 461 | break; 462 | } 463 | } 464 | 465 | fflush(stdout); 466 | } 467 | } 468 | } 469 | 470 | return 0; 471 | } 472 | -------------------------------------------------------------------------------- /src/rt_assert.h: -------------------------------------------------------------------------------- 1 | #ifndef __RT_ASSERT_H__ 2 | #define __RT_ASSERT_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #define __abort() \ 10 | { \ 11 | fprintf(stderr, "aborted at file %s:%d\n", __FILE__, __LINE__); \ 12 | abort(); \ 13 | } 14 | 15 | // runtime assert, this assert cannot be disabled by compile flags 16 | #define rt_assert(expr) \ 17 | { \ 18 | bool passed = (expr); \ 19 | if (!passed) \ 20 | { \ 21 | fprintf(stderr, "Error: rt_assert failed at %s:%d, expr = `%s`, errno = %s\n", __FILE__, __LINE__, #expr, strerror(errno)); \ 22 | exit(-1); \ 23 | } \ 24 | } 25 | 26 | #define rt_assert_eq(expr1, expr2) \ 27 | { \ 28 | const auto v1 = (expr1); \ 29 | const auto v2 = (expr2); \ 30 | if (v1 != v2) \ 31 | { \ 32 | std::stringstream msg; \ 33 | msg << "`" << #expr1 << "` (got " << v1 << ") != `" << #expr2 << "` (got " << v2 << ")"; \ 34 | fprintf(stderr, "Error: rt_assert_eq failed at %s:%d, %s.\n", __FILE__, __LINE__, msg.str().c_str()); \ 35 | exit(-1); \ 36 | } \ 37 | } 38 | 39 | #define rt_assert_ne(expr1, expr2) \ 40 | { \ 41 | const auto v1 = (expr1); \ 42 | const auto v2 = (expr2); \ 43 | if (v1 == v2) \ 44 | { \ 45 | std::stringstream msg; \ 46 | msg << "`" << #expr1 << "` (got " << v1 << ") == `" << #expr2 << "` (got " << v2 << ")"; \ 47 | fprintf(stderr, "Error: rt_assert_ne failed at %s:%d, %s.\n", __FILE__, __LINE__, msg.str().c_str()); \ 48 | exit(-1); \ 49 | } \ 50 | } 51 | 52 | #endif // __RT_ASSERT_H__ 53 | --------------------------------------------------------------------------------