cpu-policy directives are ignored on FreeBSD/non-Linux platforms(?), falling back to 1 thread
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 28/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Ít trao đổi
- Công nghệ
- c, linux
- Lĩnh vực
- operating-systems, performance
Hướng nghiên cứu
Grep for 'cpu-policy' and 'cpu_detect' in src/ and doc/configuration.txt: Linux topology discovery reads /sys, while the generic path only fetches the total CPU count and leaves one thread. Read the global-section parser and the code that applies the policy to see where it silently no-ops when nbthread is unset. The short-term goal is a fatal config error at parse time pointing at cpu-map; done means 'haproxy -c' fails on FreeBSD or the thread count matches the topology.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Detailed Description of the Problem
The cpu-policy directive (e.g., cpu-policy performance threads-per-core 1) does not work as expected on FreeBSD. Instead of automatically discovering the CPU topology and scaling the threads accordingly, HAProxy falls back to creating only a single thread.
Based on the core developer discussion in GitHub Discussion #2901, automatic CPU topology detection via /sys is currently implemented exclusively for Linux. On FreeBSD and macOS, HAProxy only fetches the total CPU count. However, instead of applying a reasonable thread allocation policy based on the available hardware limits, the parser silently ignores the directive or fails to scale, defaulting to 1 worker thread unless nbthread is explicitly defined.This likely affects all non-Linux platforms (FreeBSD, macOS, OpenBSD, NetBSD).
Expected Behavior
- Short-term mitigation (Fail-fast validation):Until a proper topology detection mechanism is implemented for this platform, HAProxy should trigger a fatal configuration error during startup or config parsing, such as:
[ALERT] (xxxx) : config : 'cpu-policy' is not implemented on this platform yet, please use 'cpu-map' instead.
- Ideal long-term solution:Ideally, this feature should function exactly as documented on non-Linux platforms, correctly leveraging the available operating system APIs to detect and utilize all available physical CPU cores.
Steps to Reproduce the Behavior
/usr/local/etc/haproxy.cfg sample:
global
#nbthread 12
cpu-policy performance threads-per-core 1
log /var/run/log local0
chroot /
user nobody
group nobody
daemon
defaults
log global
mode http
timeout connect 5s
timeout client 50s
timeout server 50s
frontend https_front
bind 0.0.0.0:80
default_backend echo_backend
backend echo_backend
balance roundrobin
server backend_server 172.16.0.1:80 id 1 check
haproxy -f /usr/local/etc/haproxy.cfg
Even when generating high multi-threaded load against the load balancer, running top -H confirms that HAProxy utilizes only a single CPU core:
h1load -d 60 -c 200 -t 24 -r 1 -P http://172.160.91:80
Do you have any idea what may have caused this?
No response
Do you have an idea how to solve the issue?
No response
What is your configuration?
Environment:
OS: FreeBSD 15.1-RELEASE-p1 (amd64)
Hardware: AMD Ryzen 9 3900X 12-Core Processor (24 threads with SMT enabled)
% sysctl hw.ncpu hw.model
hw.ncpu: 24
hw.model: AMD Ryzen 9 3900X 12-Core Processor
sysctl -qn kern.sched.topology_spec:
<groups>
<group level="1" cache-level="0">
<cpu count="24" mask="ffffff,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23</cpu>
<children>
<group level="2" cache-level="3">
<cpu count="6" mask="3f,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">0, 1, 2, 3, 4, 5</cpu>
<children>
<group level="3" cache-level="2">
<cpu count="2" mask="3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">0, 1</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="c,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">2, 3</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">4, 5</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
</children>
</group>
<group level="2" cache-level="3">
<cpu count="6" mask="fc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">6, 7, 8, 9, 10, 11</cpu>
<children>
<group level="3" cache-level="2">
<cpu count="2" mask="c0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">6, 7</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">8, 9</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="c00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">10, 11</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
</children>
</group>
<group level="2" cache-level="3">
<cpu count="6" mask="3f000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">12, 13, 14, 15, 16, 17</cpu>
<children>
<group level="3" cache-level="2">
<cpu count="2" mask="3000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">12, 13</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="c000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">14, 15</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="30000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">16, 17</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
</children>
</group>
<group level="2" cache-level="3">
<cpu count="6" mask="fc0000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">18, 19, 20, 21, 22, 23</cpu>
<children>
<group level="3" cache-level="2">
<cpu count="2" mask="c0000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">18, 19</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="300000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">20, 21</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
<group level="3" cache-level="2">
<cpu count="2" mask="c00000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">22, 23</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>
</children>
</group>
</children>
</group>
</groups>
Output of haproxy -vv
haproxy -vv
HAProxy version 3.4.1-3e888a769 2026/06/25 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2031.
Known bugs: http://www.haproxy.org/bugs/bugs-3.4.1.html
Running on: FreeBSD 15.1-RELEASE-p1 FreeBSD 15.1-RELEASE-p1 releng/15.1-0f691888dc56 GENERIC amd64
Build options :
TARGET = freebsd
CC = cc
CFLAGS = -O2 -g -O2 -pipe -fstack-protector-strong -fno-strict-aliasing -fwrapv -DFREEBSD_PORTS
OPTIONS = USE_GETADDRINFO=1 USE_OPENSSL=1 USE_ACCEPT4=1 USE_ZLIB=1 USE_CPU_AFFINITY=1 USE_TFO=1 USE_THREAD_DUMP=1 USE_QUIC=1 USE_PROMEX=1 USE_PCRE2=1 USE_PCRE2_JIT=1
DEBUG =
Feature list : -51DEGREES +ACCEPT4 +ACME -BACKTRACE +CLOSEFROM +CPU_AFFINITY -CRYPT_H -DEVICEATLAS -DL -ECH -ENGINE -EPOLL -EVPORTS +GETADDRINFO +KQUEUE -KTLS -LIBATOMIC +LIBCRYPT -LINUX_CAP -LINUX_SPLICE -LINUX_TPROXY -LUA -MATH -MEMORY_PROFILING -NETFILTER -NS -OBSOLETE_LINKER +OPENSSL -OPENSSL_AWSLC -OPENSSL_WOLFSSL -OT -PCRE +PCRE2 +PCRE2_JIT -PCRE_JIT +POLL -PRCTL +PROCCTL +PROMEX -PTHREAD_EMULATION +QUIC -QUIC_OPENSSL_COMPAT -RT -SHM_OPEN -SLZ +SSL -STATIC_PCRE -STATIC_PCRE2 +TFO +THREAD +THREAD_DUMP +TPROXY +TRACE -WURFL +ZLIB
Detected feature list :
Default settings :
bufsize = 16384, maxrewrite = 1024, maxpollevents = 200
Built with multi-threading support (MAX_TGROUPS=32, MAX_THREADS=1024, default=24).
Built with SSL library version : OpenSSL 3.5.6 7 Apr 2026
Running on SSL library version : OpenSSL 3.5.6 7 Apr 2026
SSL library supports TLS extensions : yes
SSL library supports SNI : yes
SSL library default verify directory : /etc/ssl/certs
SSL library supports : TLSv1.0 TLSv1.1 TLSv1.2 TLSv1.3
OpenSSL providers loaded : default
QUIC: connection sock-per-conn mode support : no
QUIC: GSO emission support : no
Built with the Prometheus exporter as a service
Built with zlib version : 1.3.1
Running on zlib version : 1.3.2
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with transparent proxy support using: IP_BINDANY IPV6_BINDANY
Built with PCRE2 version : 10.47 2025-10-21
PCRE2 library supports JIT : yes
Encrypted password support via crypt(3): yes
Built with clang compiler version 19.1.7 (https://github.com/llvm/llvm-project.git llvmorg-19.1.7-0-gcd708029e0b2)
Available polling systems :
kqueue : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use kqueue.
Available multiplexer protocols :
(protocols marked as <default> cannot be specified using 'proto' keyword)
quic : mode=HTTP side=FE|BE mux=QUIC flags=HTX|NO_UPG|FRAMED
qmux : mode=HTTP side=FE|BE mux=QMUX flags=HTX|NO_UPG
h2 : mode=HTTP side=FE|BE mux=H2 flags=HTX|HOL_RISK|NO_UPG
h1 : mode=HTTP side=FE|BE mux=H1 flags=HTX|NO_UPG
<default> : mode=HTTP side=FE|BE mux=H1 flags=HTX
fcgi : mode=HTTP side=BE mux=FCGI flags=HTX|HOL_RISK|NO_UPG
spop : mode=SPOP side=BE mux=SPOP flags=HOL_RISK|NO_UPG
<default> : mode=SPOP side=BE mux=SPOP flags=HOL_RISK|NO_UPG
none : mode=TCP side=FE|BE mux=PASS flags=NO_UPG
<default> : mode=TCP side=FE|BE mux=PASS flags=
Available services : prometheus-exporter
Available filters :
[BWLIM] bwlim-in
[BWLIM] bwlim-out
[CACHE] cache
[COMP] comp-req
[COMP] comp-res
[COMP] compression
[FCGI] fcgi-app
[SPOE] spoe
[TRACE] trace
Last Outputs and Backtraces
Additional Information
No response
- Ngôn ngữ chính
- C
- Star
- 6.9k
- Fork
- 976
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của haproxy/haproxy
-
type: feature
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 77/100
-
type: feature
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 63/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
-
type: code-report
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
Tất cả issue của haproxy/haproxy
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
compiler-explorer/compiler-explorer#9272 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
semantic-reasoning/wirelog#2163 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 3 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 63/100
Xinyuan-LilyGO/T-Display-S3#352 · 3 bình luận ·
-
documentation severity/minor
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày