From 78e9ba927d0c6f15e0388c8a5e056d1e82e21e88 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Sun, 27 Sep 2026 07:37:44 +0100 Subject: Choose the connection threads with --threads auto One connection thread for each CPU the process may run on (its affinity, or the online CPUs), less the one the owner of an app with states takes: three CPUs give two connection threads and the owner. The default stays one thread. --- docs/design/008-module-format.md | 1 + prototypes/connections/serve.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md index 3acaee6..dd16c90 100644 --- a/docs/design/008-module-format.md +++ b/docs/design/008-module-format.md @@ -303,6 +303,7 @@ text·리스트가 남을 때만 위치를 유지한다. - **저장소 핸들.** 문서와 상태를 저장소 핸들(`pure_store_data`)로 열어 파일 매핑 하나를 공유하고, 묶음마다 한 번만 저장소가 바뀌었는지 본다. - **연결 스레드와 소유자.** `--threads N`은 스레드마다 같은 포트의 리스너(`SO_REUSEPORT`), epoll, 런타임 코어를 둔다. + `--threads auto`는 프로세스가 쓸 수 있는 CPU마다 하나를 두고, 상태를 가진 앱이면 소유자 몫으로 하나를 뺀다. 키별 문서만 가진 모듈은 스레드마다 앱과 저장소 핸들을 두고 저장소 말고는 아무것도 나누지 않는다. 상태를 가진 모듈은 상태의 소유자가 하나여야 하므로, 연결 스레드가 하나여도 따로 소유자 스레드가 앱을 돌린다. 연결 스레드는 요청을 받고 해석하고 답을 쓰는 일(시스템 호출이 대부분이다)을 나눠 맡고, 입력과 문서 요청을 소유자에게 넘긴다. diff --git a/prototypes/connections/serve.c b/prototypes/connections/serve.c index 24248b6..1eb5ca5 100644 --- a/prototypes/connections/serve.c +++ b/prototypes/connections/serve.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1650,6 +1651,16 @@ static void stop_shard(Host *host) { free(host->views); } +/* --threads auto: a connection thread for each CPU this process may run on, + * less the one the owner of an app with states takes. */ +static unsigned auto_threads(bool owner) { + cpu_set_t set; + long cpus = sched_getaffinity(0, sizeof(set), &set) ? sysconf(_SC_NPROCESSORS_ONLN) : CPU_COUNT(&set); + if (cpus < 1) cpus = 1; + if (owner && cpus > 1) --cpus; + return cpus > 256 ? 256 : (unsigned)cpus; +} + int main(int argc, char **argv) { static PureModule module; static Owner owner; @@ -1665,6 +1676,7 @@ int main(int argc, char **argv) { else if (!strcmp(argv[i], "--port") && number(argv[i + 1], 65535, &value)) port = (unsigned)value; else if (!strcmp(argv[i], "--budget") && number(argv[i + 1], SIZE_MAX, &value) && value) budget = (size_t)value; else if (!strcmp(argv[i], "--connections") && number(argv[i + 1], 1u << 20, &value) && value) capacity = (size_t)value; + else if (!strcmp(argv[i], "--threads") && !strcmp(argv[i + 1], "auto")) threads = 0; else if (!strcmp(argv[i], "--threads") && number(argv[i + 1], 256, &value) && value) threads = (unsigned)value; else if (!strcmp(argv[i], "--timeout-ms") && number(argv[i + 1], 3600000, &value) && value) timeout_ms = value; else goto usage; @@ -1672,6 +1684,7 @@ int main(int argc, char **argv) { uint32_t show, edit; bool documents; if (!module_path || !store || !load_module(&module, module_path, &documents, &show, &edit)) goto usage; + if (!threads) threads = auto_threads(module.states); if (pure_store_init(store) != PURE_OK) { fputs("Cannot initialize the store directory\n", stderr); return 1; } signal(SIGPIPE, SIG_IGN); struct sigaction stop_action = {.sa_handler = stop}; @@ -1746,7 +1759,7 @@ int main(int argc, char **argv) { free(thread); return 0; usage: - fputs("pure-serve --module FILE.pmod --store DIRECTORY [--port 8767] [--threads 1] [--budget BYTES] " + fputs("pure-serve --module FILE.pmod --store DIRECTORY [--port 8767] [--threads 1|N|auto] [--budget BYTES] " "[--connections 1024] [--timeout-ms 10000]\n", stderr); return 2; } -- cgit v1.2.3