From fd012b6c59c34d9621b142ff13710e540031e65d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 3 Nov 2025 09:30:47 +0100 Subject: [PATCH] OPTIM: proxy: move atomically access fields out of the read-only ones Perf top showed that h1_snd_buf() was having great difficulties accessing the proxy's server_id_hdr_name field in the middle of the headers loop. Moving the assignment out of the loop to a local variable moved the problem there as well: | if (!(h1m->flags & H1_MF_RESP) && isttest(h1c->px->server_id_hdr_n 0.10 |20b0: mov -0x120(%rbp),%rdi 1.33 | mov 0x60(%rdi),%r10 0.01 | test %eax,%eax 0.18 | jne 2118 12.87 | mov 0x350(%r10),%rdi 0.01 | test %rdi,%rdi 0.05 | je 2118 | mov 0x358(%r10),%r11 It turns out that there are several atomically accessed fields in its vicinity, causing the cache line to bounce all the time. Let's collect the few frequently changed fields and place them together at the end of the structure, and plug the 32-bit hole with another isolated field. Doing so also reduced a little bit the cost of decrementing be->be_conn in process_stream(), and overall the HTTP/1 performance increased by about 1% both on ARM and x86_64. --- include/haproxy/proxy-t.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index 055141d0f..f02946552 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -356,7 +356,8 @@ struct proxy { struct server *srv, *defsrv; /* known servers; default server configuration */ struct lbprm lbprm; /* load-balancing parameters */ int srv_act, srv_bck; /* # of servers eligible for LB (UP|!checked) AND (enabled+weight!=0) */ - int served; /* # of active sessions currently being served */ + int load_server_state_from_file; /* location of the file containing server state. + * flag PR_SRV_STATE_FILE_* */ int cookie_len; /* strlen(cookie_name), computed only once */ struct server *ready_srv; /* a server being ready to serve requests */ char *cookie_domain; /* domain used to insert the cookie */ @@ -401,9 +402,6 @@ struct proxy { char *id; /* proxy id (name), indexed by below */ char *desc; /* proxy description */ struct proxy_per_tgroup *per_tgrp; /* array of per-tgroup stuff such as queues */ - unsigned int queueslength; /* Sum of the length of each queue */ - int totpend; /* total number of pending connections on this instance (for stats) */ - unsigned int feconn, beconn; /* # of active frontend and backends streams */ unsigned int fe_sps_lim; /* limit on new sessions per second on the frontend */ unsigned int fullconn; /* #conns on backend above which servers are used at full load */ struct ist server_id_hdr_name; /* the header to use to send the server id (name) */ @@ -495,8 +493,6 @@ struct proxy { struct email_alertq *queues; /* per-mailer alerts queues */ } email_alert; - int load_server_state_from_file; /* location of the file containing server state. - * flag PR_SRV_STATE_FILE_* */ char *server_state_file_name; /* used when load_server_state_from_file is set to * PR_SRV_STATE_FILE_LOCAL. Give a specific file name for * this backend. If not specified or void, then the backend @@ -508,6 +504,12 @@ struct proxy { EXTRA_COUNTERS(extra_counters_fe); EXTRA_COUNTERS(extra_counters_be); + + THREAD_ALIGN(64); + unsigned int queueslength; /* Sum of the length of each queue */ + int served; /* # of active sessions currently being served */ + int totpend; /* total number of pending connections on this instance (for stats) */ + unsigned int feconn, beconn; /* # of active frontend and backends streams */ }; struct switching_rule {