请考虑以下代码:
extern int conn_fds[MAX_CLIENTS];
extern int fl_conn_indexes[MAX_CLIENTS];
extern int fl_req_bufs[MAX_CLIENTS];
extern struct epoll_event estab_events[MAX_THREADS];
extern req_buf_t req_bufs[MAX_REQ_BUFS];
extern int fl_req_bufs_top;
extern int conn_statuses[MAX_CLIENTS];
extern int fl_conn_indexes_top;
extern tcpl_nc_t nc_http_list;
extern struct sockaddr_in conn_addresses[MAX_CLIENTS];
void accept_connections(unsigned int num_conns) {
int fds[MAX_THREADS];
int conn_indexes[MAX_THREADS];
int conn_idx=0;
int new_bottom;
socklen_t slenghts[MAX_THREADS];
void *labels1[MAX_THREADS] = {&&a0,&&a1,&&a2,&&a3,&&a4,&&a5,&&a6,&&a7,&&a8,&&a9,&&a10,&&a11,&&a12,&&a13,&&a14,&&a15};
void *labels2[MAX_THREADS] = {&&b0,&&b1,&&b2,&&b3,&&b4,&&b5,&&b6,&&b7,&&b8,&&b9,&&b10,&&b11,&&b12,&&b13,&&b14,&&b15};
void *labels3[MAX_THREADS] = {&&c0,&&c1,&&c2,&&c3,&&c4,&&c5,&&c6,&&c7,&&c8,&&c9,&&c10,&&c11,&&c12,&&c13,&&c14,&&c15};
new_bottom=fl_conn_indexes_top-num_conns;
if (new_bottom<=0) return;
goto *labels1[num_conns];
a15:
conn_indexes[MAX_THREADS- 1]=fl_conn_indexes[fl_conn_indexes_top- 1];
a14:
conn_indexes[MAX_THREADS- 2]=fl_conn_indexes[fl_conn_indexes_top- 2];
a13:
conn_indexes[MAX_THREADS- 3]=fl_conn_indexes[fl_conn_indexes_top- 3];
a12:
conn_indexes[MAX_THREADS- 4]=fl_conn_indexes[fl_conn_indexes_top- 4];
a11:
conn_indexes[MAX_THREADS- 5]=fl_conn_indexes[fl_conn_indexes_top- 5];
a10:
conn_indexes[MAX_THREADS- 6]=fl_conn_indexes[fl_conn_indexes_top- 6];
a9:
conn_indexes[MAX_THREADS- 7]=fl_conn_indexes[fl_conn_indexes_top- 7];
a8:
conn_indexes[MAX_THREADS- 8]=fl_conn_indexes[fl_conn_indexes_top- 8];
a7:
conn_indexes[MAX_THREADS- 9]=fl_conn_indexes[fl_conn_indexes_top- 9];
a6:
conn_indexes[MAX_THREADS-10]=fl_conn_indexes[fl_conn_indexes_top-10];
a5:
conn_indexes[MAX_THREADS-11]=fl_conn_indexes[fl_conn_indexes_top-11];
a4:
conn_indexes[MAX_THREADS-12]=fl_conn_indexes[fl_conn_indexes_top-12];
a3:
conn_indexes[MAX_THREADS-13]=fl_conn_indexes[fl_conn_indexes_top-13];
a2:
conn_indexes[MAX_THREADS-14]=fl_conn_indexes[fl_conn_indexes_top-14];
a1:
conn_indexes[MAX_THREADS-15]=fl_conn_indexes[fl_conn_indexes_top-15];
a0:
conn_indexes[MAX_THREADS-16]=fl_conn_indexes[fl_conn_indexes_top-16];
fl_conn_indexes_top=fl_conn_indexes_top-num_conns;
goto *labels2[num_conns];
b15:
conn_fds[conn_indexes[MAX_THREADS- 1]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 1]],&slenghts[MAX_THREADS- 1]);
b14:
conn_fds[conn_indexes[MAX_THREADS- 2]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 2]],&slenghts[MAX_THREADS- 2]);
b13:
conn_fds[conn_indexes[MAX_THREADS- 3]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 3]],&slenghts[MAX_THREADS- 3]);
b12:
conn_fds[conn_indexes[MAX_THREADS- 4]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 4]],&slenghts[MAX_THREADS- 4]);
b11:
conn_fds[conn_indexes[MAX_THREADS- 5]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 5]],&slenghts[MAX_THREADS- 5]);
b10:
conn_fds[conn_indexes[MAX_THREADS- 6]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 6]],&slenghts[MAX_THREADS- 6]);
b9:
conn_fds[conn_indexes[MAX_THREADS- 7]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 7]],&slenghts[MAX_THREADS- 7]);
b8:
conn_fds[conn_indexes[MAX_THREADS- 8]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 8]],&slenghts[MAX_THREADS- 8]);
b7:
conn_fds[conn_indexes[MAX_THREADS- 9]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 9]],&slenghts[MAX_THREADS- 9]);
b6:
conn_fds[conn_indexes[MAX_THREADS-10]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-10]],&slenghts[MAX_THREADS-10]);
b5:
conn_fds[conn_indexes[MAX_THREADS-11]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-11]],&slenghts[MAX_THREADS-11]);
b4:
conn_fds[conn_indexes[MAX_THREADS-12]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-12]],&slenghts[MAX_THREADS-12]);
b3:
conn_fds[conn_indexes[MAX_THREADS-13]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-13]],&slenghts[MAX_THREADS-13]);
b2:
conn_fds[conn_indexes[MAX_THREADS-14]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-14]],&slenghts[MAX_THREADS-14]);
b1:
conn_fds[conn_indexes[MAX_THREADS-15]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-15]],&slenghts[MAX_THREADS-15]);
b0:
conn_fds[conn_indexes[MAX_THREADS-16]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS-16]],&slenghts[MAX_THREADS-16]);
goto *labels3[num_conns];
c15:
conn_statuses[conn_indexes[MAX_THREADS- 1]]=CONN_STATUS_READING;
c14:
conn_statuses[conn_indexes[MAX_THREADS- 2]]=CONN_STATUS_READING;
c13:
conn_statuses[conn_indexes[MAX_THREADS- 3]]=CONN_STATUS_READING;
c12:
conn_statuses[conn_indexes[MAX_THREADS- 4]]=CONN_STATUS_READING;
c11:
conn_statuses[conn_indexes[MAX_THREADS- 5]]=CONN_STATUS_READING;
c10:
conn_statuses[conn_indexes[MAX_THREADS- 6]]=CONN_STATUS_READING;
c9:
conn_statuses[conn_indexes[MAX_THREADS- 7]]=CONN_STATUS_READING;
c8:
conn_statuses[conn_indexes[MAX_THREADS- 8]]=CONN_STATUS_READING;
c7:
conn_statuses[conn_indexes[MAX_THREADS- 9]]=CONN_STATUS_READING;
c6:
conn_statuses[conn_indexes[MAX_THREADS-10]]=CONN_STATUS_READING;
c5:
conn_statuses[conn_indexes[MAX_THREADS-11]]=CONN_STATUS_READING;
c4:
conn_statuses[conn_indexes[MAX_THREADS-12]]=CONN_STATUS_READING;
c3:
conn_statuses[conn_indexes[MAX_THREADS-13]]=CONN_STATUS_READING;
c2:
conn_statuses[conn_indexes[MAX_THREADS-14]]=CONN_STATUS_READING;
c1:
conn_statuses[conn_indexes[MAX_THREADS-15]]=CONN_STATUS_READING;
c0:
conn_statuses[conn_indexes[MAX_THREADS-16]]=CONN_STATUS_READING;
}
我在这里所做的是并行处理MAX_THREADS数量的连接。循环是故意展开的,是为了速度。但是代码很长。我需要使用宏来减少它,有点像这样:
extern int conn_fds[MAX_CLIENTS];
extern int fl_conn_indexes[MAX_CLIENTS];
extern int fl_req_bufs[MAX_CLIENTS];
extern struct epoll_event estab_events[MAX_THREADS];
extern req_buf_t req_bufs[MAX_REQ_BUFS];
extern int fl_req_bufs_top;
extern int conn_statuses[MAX_CLIENTS];
extern int fl_conn_indexes_top;
extern tcpl_nc_t nc_http_list;
extern struct sockaddr_in conn_addresses[MAX_CLIENTS];
void accept_connections(unsigned int num_conns) {
int fds[MAX_THREADS];
int conn_indexes[MAX_THREADS];
int conn_idx=0;
int new_bottom;
socklen_t slenghts[MAX_THREADS];
void *labels1[MAX_THREADS] = {&&a0,&&a1,&&a2,&&a3,&&a4,&&a5,&&a6,&&a7,&&a8,&&a9,&&a10,&&a11,&&a12,&&a13,&&a14,&&a15};
void *labels2[MAX_THREADS] = {&&b0,&&b1,&&b2,&&b3,&&b4,&&b5,&&b6,&&b7,&&b8,&&b9,&&b10,&&b11,&&b12,&&b13,&&b14,&&b15};
void *labels3[MAX_THREADS] = {&&c0,&&c1,&&c2,&&c3,&&c4,&&c5,&&c6,&&c7,&&c8,&&c9,&&c10,&&c11,&&c12,&&c13,&&c14,&&c15};
new_bottom=fl_conn_indexes_top-num_conns;
if (new_bottom<=0) return;
goto *labels1[num_conns];
LOOP(1,MAX_THREADS) {
a{ITERATOR}:
conn_indexes[MAX_THREADS- {ITERATOR}]=fl_conn_indexes[fl_conn_indexes_top- {ITERATOR}];
}
fl_conn_indexes_top=fl_conn_indexes_top-num_conns;
goto *labels2[num_conns];
LOOP(1,MAX_THREADS) {
b{ITERATOR}:
conn_fds[conn_indexes[MAX_THREADS- {ITERATOR}]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[MAX_THREADS- 1{ITERATOR}]],&slenghts[MAX_THREADS- {ITERATOR}]);
}
goto *labels3[num_conns];
LOOP(1,MAX_THREADS) {
c{ITERATOR}:
conn_statuses[conn_indexes[MAX_THREADS- {ITERATOR}]]=CONN_STATUS_READING;
}
}
{iterator} 在 LOOP() 内部从 1 变为 MAX_THREADS标签被取消是因为连接数可以低于MAX_THREADS并且我必须跳过空变量,否则我会得到段错误。
这可以通过GCC的预处理器轻松实现吗?如果没有,也许我可以使用 m4,但是如何将 m4 与 GCC 集成以实现舒适的开发。因为,我将经常在源代码中编辑这些宏以及许多其他文件,并且需要易于编码。
将非常感谢您的帮助
如果您确实需要m4
答案:
dnl usage: unroll(var, initial, max, code)
dnl e.g. unroll(`i', 0, 10, ``total += arr[i]'')
dnl The above goes from 0 to 9, it does not include the final 10.
define(`unroll',
`define(`$1', `$2')ifelse(eval($2 < $3),
1,
`$4`'unroll(`$1',incr($2),$3,`$4')',
`undefine(`$1')')')dnl
void accept_connections(unsigned int num_conns) {
int fds[MAX_THREADS];
int conn_indexes[MAX_THREADS];
int conn_idx=0;
int new_bottom;
socklen_t slenghts[MAX_THREADS];
void *labels1[MAX_THREADS] = {unroll(`i', 0, 16, `&&a`'i,')};
void *labels2[MAX_THREADS] = {unroll(`i', 0, 16, `&&b`'i,')};
void *labels3[MAX_THREADS] = {unroll(`i', 0, 16, `&&c`'i,')};
new_bottom=fl_conn_indexes_top-num_conns;
if (new_bottom<=0) return;
define(`MAX_NUM_CONNS', 16)
goto *labels1[num_conns];
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
a`'eval(MAX_NUM_CONNS() - count):
conn_indexes[MAX_THREADS - count]=fl_conn_indexes[fl_conn_indexes_top - count];
')dnl
fl_conn_indexes_top=fl_conn_indexes_top-num_conns;
goto *labels2[num_conns];
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
define(`index', `MAX_THREADS - count')dnl
b`'eval(MAX_NUM_CONNS() - count):
conn_fds[conn_indexes[index]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[index]],&slenghts[index]);
')dnl
undefine(`index')
goto *labels3[num_conns];
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
c`'eval(MAX_NUM_CONNS() - count):
conn_statuses[conn_indexes[MAX_THREADS - count]]=CONN_STATUS_READING;
')dnl
}
特别注意代码中的宏:define
、unroll
、eval
、MAX_NUM_CONNS
、count
、index
、i
。还要注意 m4 喜欢的古怪引用。
我可以对此提出改进建议(无论您是否使用 m4
)。您在这里的 gotos 紧随其后的用例已经完全被一个更知名的控制结构所覆盖:switch
(因为fallthrough是没有break
的默认行为):
define(`MAX_NUM_CONNS', 16)
switch (num_conns) {
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
case eval(MAX_NUM_CONNS() - count):
conn_indexes[MAX_THREADS - count]=fl_conn_indexes[fl_conn_indexes_top - count];
')dnl
}
fl_conn_indexes_top=fl_conn_indexes_top-num_conns;
switch (num_conns) {
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
define(`index', `MAX_THREADS - count')dnl
case eval(MAX_NUM_CONNS() - count):
conn_fds[conn_indexes[index]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[index]],&slenghts[index]);
')dnl
}
undefine(`index')
switch (num_conns) {
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
case eval(MAX_NUM_CONNS() - count):
conn_statuses[conn_indexes[MAX_THREADS - count]]=CONN_STATUS_READING;
')dnl
}
如果将此转换为交换机,则可以删除标签数组。
最后,也许它都可以是一个开关:
define(`MAX_NUM_CONNS', 16)
switch (num_conns) {
unroll(`count', 1, incr(MAX_NUM_CONNS()), `dnl
define(`index', `MAX_THREADS - count')dnl
case eval(MAX_NUM_CONNS() - count):
conn_indexes[index]=fl_conn_indexes[fl_conn_indexes_top - count];
conn_fds[conn_indexes[index]]=accept(nc_http_list.sock_fd,(struct sockaddr*) &conn_addresses[conn_indexes[index]],&slenghts[index]);
conn_statuses[conn_indexes[index]]=CONN_STATUS_READING;
')dnl
}
undefine(`index')
fl_conn_indexes_top=fl_conn_indexes_top-num_conns;
请注意,我已将fl_conn_indexes_top
修改移至整个展开循环完成后 - 我不确定这是否有效,因为它取决于何时读取或写入该变量。你可以在那里做出判断。
正如我在评论中提到的,这也可以使用编译器标志来完成。GCC 支持 -funroll-loops
选项,该选项在编译器级别为您执行此操作。GCC也支持-fprofile-use
,当从-fprofile-generate
提供配置文件时)将展开循环,这被证明会导致性能问题。
最后:
我认为这都是过早的优化。我强烈怀疑循环的比较检查是每次迭代调用accept
时的瓶颈!
你可以用 chaos-pp 预处理器库滥用 C 预处理器
#include <chaos/preprocessor/arithmetic/dec.h>
#include <chaos/preprocessor/config.h>
#include <chaos/preprocessor/lambda/ops.h>
#include <chaos/preprocessor/logical/bool.h>
#include <chaos/preprocessor/recursion/expr.h>
#include <chaos/preprocessor/repetition/for.h>
#define PRED(s, x) CHAOS_PP_BOOL(x)
#define OP(s, x) CHAOS_PP_DEC(x)
#define CONN_IDX(s , idx)
a##idx:
conn_indexes[MAX_THREADS - (16 - idx)]=fl_conn_indexes[fl_conn_indexes_top - (16 - idx)];
CHAOS_PP_EXPR(CHAOS_PP_FOR(PRED, OP, CONN_IDX, 15))
(格式化的)输出为:
a15:
conn_indexes[MAX_THREADS - (16 - 15)]=fl_conn_indexes[fl_conn_indexes_top - (16 - 15)];
a14:
conn_indexes[MAX_THREADS - (16 - 14)]=fl_conn_indexes[fl_conn_indexes_top - (16 - 14)];
...