From 83286a0722be240690c134d9c6c75b2da6e94e8a Mon Sep 17 00:00:00 2001 From: eunhhu Date: Thu, 1 Oct 2026 09:18:23 +0100 Subject: Say what one sending loop showed (017 2b, research 113) The loop alone slowed four links to half: woken by every record queued, it chased the owner a record at a time. Pushing once a turn made links 1.6 times as fast, with threads or the loop alike; the loop's own cost is within the noise. Twenty outputs now add two threads, not 21. --- docs/design/017-apps-on-one-host.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'docs/design/017-apps-on-one-host.md') diff --git a/docs/design/017-apps-on-one-host.md b/docs/design/017-apps-on-one-host.md index aaaef51..3ffdc0f 100644 --- a/docs/design/017-apps-on-one-host.md +++ b/docs/design/017-apps-on-one-host.md @@ -1,7 +1,7 @@ # 017 — 한 호스트의 여러 앱: 차례, 예산, 실패 경계 -작성일: 2026-10-01. 상태: 1·2단계 구현, 검사로 고정하고 쟀다([111](../research/111-apps-on-one-host.md), -[112](../research/112-sending-between-apps.md)). 2b는 착수 기준을 적었다. 3단계는 설계. +작성일: 2026-10-01. 상태: 1·2단계와 2b 구현, 검사로 고정하고 쟀다([111](../research/111-apps-on-one-host.md), +[112](../research/112-sending-between-apps.md), [113](../research/113-one-sending-loop.md)). 3단계는 설계. [외부 리뷰 004](../outside-feedback/feedback-004.md)의 "구현 방향에 대한 평가" 셋째에서 시작한다. 작은 OS의 운영 모델( [007](007-execution-domains.md))을 Pure가 실제로 갖게 하는 단계다. @@ -175,12 +175,17 @@ counter apps/count.pmod stores/counter **2b: 보내는 루프 하나.** 보냄마다의 스레드(전달선 하나, 링크 하나에 하나씩)를 호스트의 보내는 스레드 하나로 모은다. 출력을 가진 앱은 보냄마다 스레드 하나를 더해 왔다. 앱마다 스레드를 두지 않는다는 원칙에 어긋나는 마지막 자리다. -- 루프 하나(`pure-send`)가 epoll 하나에 링크의 UDP 소켓과 전달선의 TCP 소켓, 깨움 하나를 둔다. 기다리는 시간은 링크들의 다음 때와 - 전달선들의 쉼 가운데 가장 이른 것이다. 출구에 보냄이 쌓이면 루프를 깨운다(자고 있을 때 한 번). +- 루프 하나(`pure-send`, `link/sending.c`)가 epoll 하나에 링크의 UDP 소켓과 전달선의 TCP 소켓, 깨움 하나를 둔다. 보내는 쪽은 + 루프에 들어오며 자기 바퀴(round)와 기다릴 소켓을 준다. 루프는 원하는 것만 돈다. 소켓이 준비됐거나, 밀렸거나, 원한 때가 온 + 것이다. 기다리는 시간은 그 때들 가운데 가장 이른 것이다. +- 소유자는 출구에 보냄을 쌓고, 차례의 것을 다 쌓은 뒤 출구마다 한 번 민다(`pure_link_push`, `pure_wire_push`). 미는 것이 루프를 + 깨운다(자고 있을 때 한 번). 쌓기마다 깨우면 루프가 기록을 하나씩 따라잡으며 작은 패킷을 낸다(아래). - 링크(2b-1): 지금 스레드가 한 바퀴에 하던 일을 루프의 한 바퀴에서 링크마다 한다. 답 받기, 시각, 보내기다. 받는 쪽을 다시 찾는 이름 찾기(DNS)는 그 자리에서 기다린다. 프로브 셋이 답을 못 받았을 때뿐이라 드물지만, 그동안 다른 보냄도 멈춘다. 이것을 밝힌다. -- 전달선(2b-2): 비블로킹 HTTP/1.1 클라이언트의 상태기다(연결, TLS, 요청 쓰기, 답 읽기, 쉼). TLS는 crypto의 함수 표에 비블로킹 - 단계를 더한다. 이름 찾기는 연결할 때 기다린다(링크와 같다). +- 전달선(2b-2): 비블로킹 HTTP/1.1 클라이언트의 상태기다(연결, TLS, 요청 쓰기, 답 읽기, 쉼). 바퀴는 소켓이 받는 데까지 가고, + 소켓이나 마감(아무것도 움직이지 않은 10초)을 기다린다. 답은 오는 대로 읽는다. 머리를 다 받고, 크기가 적힌 몸은 세어 내려가고, + 조각난(chunked) 몸은 자랄 때마다 처음부터 다시 읽는다(드물고 작다). TLS는 crypto의 함수 표(판 6)에 핸드셰이크의 걸음을 + 더했다. 이름 찾기는 연결할 때 기다린다(링크와 같다). **2b의 착수 기준.** @@ -190,6 +195,17 @@ counter apps/count.pmod stores/counter - 통과 조건(RAM의 Pi 5, 전과 후 번갈아): 112의 링크 측정(두 앱, 루프백 링크 하나)과 같은 방식의 전달선 측정(HTTP로 받는 앱)에서 처리량의 중앙값이 5% 넘게 낮지 않다. 링크 넷이 함께 보낼 때 처리량의 합이 10% 넘게 낮지 않다. +### 2b에서 알게 된 것 + +- **깨움의 단위가 문제였다.** 루프만 바꾼 첫 구현(`32f96b3`)은 링크 넷을 초당 58만 건에서 27만 건으로 늦췄다. 쌓기마다 깨우니 + 루프가 소유자의 쌓기를 하나씩 따라잡고 잠들기를 되풀이했다. 루프가 기다린 번이 17.7만, 링크의 바퀴가 70만, 패킷이 9.2만이었다. + 차례마다 한 번 밀고 원하는 링크만 돌게 하자(`6d3c3c2`) 링크 넷이 80만 건이 됐다. 같은 밀기를 링크마다 스레드인 전 구현에 + 붙여도 80만 건이다. 빨라진 것은 밀기 덕이고, 루프 자체의 값은 이 측정의 흔들림(1–3%) 안이다. +- **결과.** 링크와 전달선 스무 개를 가진 호스트의 스레드가 24개에서 5개다(출력이 없으면 3개). 전달선 하나 +0.7%, 넷 −2.3%(보냄 + 하나의 CPU는 같다), 링크 하나 +63%, 넷 +67%. 검사가 모두 초록이다. 커밋: Pure `32f96b3`(링크의 루프), `6d3c3c2`(밀기), + `b6bcd4c`(루프를 따로), `eb3812a`(전달선의 상태기), `56eb228`(측정). +- **남은 값.** 이름 찾기(DNS)가 루프를 멈추고, 전달선 넷의 요청이 차례로 쓰이고 읽힌다. 둘 다 측정에 보일 때 다룬다. + ## 2단계의 착수 기준 - **바꿀 결정:** 같은 호스트의 앱 사이를 링크(소켓, 봉인)가 아니라 안쪽 출구로 건넬지다. 아래를 채우지 못하면 같은 호스트의 -- cgit v1.2.3