mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-11-03 16:45:53 +00:00
C++20 port 16/16: config parsing on arenas, unit tests in C++ (#3080)
* Rename test_jconf.c to test_jconf_cpp.cpp * Parse the config file on arenas read_jconf now reads the file and builds the JSON tree in a scratch arena that is released before it returns, and copies the parsed strings into one process-lifetime arena instead of a malloc per string. parse_addr and the config parser share one address splitter. Port test_jconf to C++ and cover every field copied out of the parse tree, a re-read, and the densest file the size limit accepts. * tests: rename remaining C unit tests to .cpp (no content changes) * tests: port remaining C unit tests to the C++ test harness Convert acl, acl_literal, aead2022, base64, buffer, cache (legacy reference), crypto, ipset, ipset_reference, json, netutils, ppbloom, process, ref, ssurl and utils tests to test_helpers.hpp. ctest names are unchanged; every assertion is kept. Build the ported sources with the strict C++ warning set. * Run clang-tidy on every ported test The test regex skipped file names with digits (test_aead2022_cpp.cpp, test_base64_cpp.cpp); include them, fix the two optional accesses it then reports, and build test_jconf with the strict warning set. * docs: per-connection RSS on Linux against the C relay * test_jconf: check read_jconf results before using them
This commit is contained in:
+8
-2
@@ -113,7 +113,12 @@ Pools are reserved at startup and only touched slots become resident.
|
||||
3. Event layer over libuv (`src/event/`).
|
||||
4. Crypto codecs held by value: AEAD, stream and AEAD-2022.
|
||||
5. Services: the cache on a fixed slab, `IntrusiveList` for ACL rules and
|
||||
the manager, the pooled resolver.
|
||||
the manager, the pooled resolver, and `read_jconf` on arenas (the file and
|
||||
JSON tree in a scratch arena released before it returns, the parsed
|
||||
strings in one process-lifetime arena). ACL rules and IP-set nodes still
|
||||
come from `malloc` at startup: the IP-set trie frees nodes as it merges
|
||||
prefixes, and its size depends on the ACL file, so a bump arena would
|
||||
have to reserve for the worst case.
|
||||
6. One TCP engine for ss-tunnel, ss-local, ss-redir and ss-server.
|
||||
7. One UDP engine.
|
||||
8. Library heaps for libuv, c-ares and Mbed TLS, `heap_seal()`, and the
|
||||
@@ -122,7 +127,8 @@ Pools are reserved at startup and only touched slots become resident.
|
||||
(`ss_local_start`/`stop`/`wait`/`destroy`) and the RAII
|
||||
`shadowsocks/shadowsocks.hpp`.
|
||||
10. Removal of `ss_event`, the C resolver, the C codecs (now test oracles),
|
||||
uthash and `ss_list`.
|
||||
uthash and `ss_list`, and the unit tests ported to C++
|
||||
(`tests/test_helpers.hpp`).
|
||||
|
||||
## Allocation audit
|
||||
|
||||
|
||||
+17
-2
@@ -63,8 +63,23 @@ RSS with 1,000 established, idle connections through ss-local and ss-server
|
||||
|
||||
Each connection slot carries about 104 KiB of inline buffers, against roughly
|
||||
58 KiB that the C relay allocated on demand. The pool is reserved virtually at
|
||||
startup and only touched slots become resident. A shared buffer pool with read
|
||||
backpressure would cut this; it is the main open trade-off of the rewrite.
|
||||
startup and only the touched pages of a slot become resident.
|
||||
|
||||
The table above was taken on Apple Silicon, whose 16 KiB pages round every
|
||||
touched buffer up to a whole page. The same test on Linux (4 KiB pages, GCC,
|
||||
Alpine container, aes-256-gcm, one small request per connection) gives:
|
||||
|
||||
| | C server | C++ server | C local | C++ local |
|
||||
|---|---:|---:|---:|---:|
|
||||
| idle | 1,380 KiB | 1,812 KiB | 1,248 KiB | 1,684 KiB |
|
||||
| 1,000 connections | 27,604 KiB | 37,248 KiB | 24,744 KiB | 34,236 KiB |
|
||||
| per connection | 26.2 KiB | 35.4 KiB | 23.5 KiB | 32.6 KiB |
|
||||
|
||||
So the fixed slots cost about 9 KiB per connection more than C on Linux.
|
||||
Construction does not zero-fill the buffers (a user-provided `FixedBuffer`
|
||||
constructor changed nothing), so the difference is page granularity across
|
||||
the separate inline buffers. A shared buffer pool with read backpressure
|
||||
would cut it; it is the main open trade-off of the rewrite.
|
||||
|
||||
### UDP
|
||||
|
||||
|
||||
Reference in New Issue
Block a user