diff options
| author | eunhhu <[email protected]> | 2026-10-04 21:52:34 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-04 21:52:34 +0100 |
| commit | 93785a2e38699b4e65020153f434de9db5e8e098 (patch) | |
| tree | 1ce7f64d1b466fbc8cef452aaffdf5c174b626e4 /docs/research | |
| parent | 85a57b8eb2704565ef646f2415eedcd1386a4afd (diff) | |
| download | pure-93785a2e38699b4e65020153f434de9db5e8e098.tar.gz pure-93785a2e38699b4e65020153f434de9db5e8e098.zip | |
Measure views off the connection threads: writes' tail as with the CPU shared, two askers 1.95 times one (122)
Diffstat (limited to 'docs/research')
| -rw-r--r-- | docs/research/122-views-off-the-connection-threads.md | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/docs/research/122-views-off-the-connection-threads.md b/docs/research/122-views-off-the-connection-threads.md new file mode 100644 index 0000000..5af9c09 --- /dev/null +++ b/docs/research/122-views-off-the-connection-threads.md @@ -0,0 +1,84 @@ +# 122 — 긴 보기를 연결 스레드 밖에서 + +2026-10-04. [020](../design/020-computing-faster.md)의 2단계(본문이 있는 보기를 보기의 스레드에서)를 잰다. 기준은 구현하기 +전에 적어 커밋했다(`1d8c1f1`). 만든 것은 `2fb1da2`이고, 만들면서 정한 것은 020의 "2단계에서 정한 것"에 적었다. + +## 쉬운 말로 + +- **계산하는 보기가 이제 다른 연결을 기다리게 하지 않는다.** 본문이 있는 보기(BFS 같은)는 보기의 스레드가 계산하고, 연결 스레드는 + 그동안 다른 연결을 읽고 쓴다. 연결 둘이 BFS 보기를 쉬지 않고 묻는 동안 쓰기의 최대 지연이 11 ms다. 같은 코어를 다른 프로세스와 + 나눌 때와 같다(1.0배, 기준 2배 이하). 전처럼 연결 스레드가 계산하면 76 ms(8.2배)다. +- **보기가 연결의 자리와 상관없이 나란히 돈다.** 연결 스레드 하나에서 묻는 연결 둘이 하나의 1.95배를 받는다(기준 1.8배, 전에는 + 1.0배). 전에는 두 연결이 같은 연결 스레드에 떨어지면(커널이 정한다) 차례로 돌아 초당 36번, 다른 스레드면 70번이었다. 이제 늘 + 56–60번이다. +- **짧은 보기는 그대로다.** 식 하나의 보기(`total`)는 연결 스레드가 계산하고, 그 읽기는 전과 같다(−0.2%, 기준 3% 안). +- 보기를 계산하는 데 드는 CPU는 그대로다. 쓰기가 줄어드는 몫(42%만 남는다)은 다른 프로세스와 코어를 나눌 때와 같다(39.5%). + +## 결과 + +원시 결과와 명령은 [037-view-workers](../../research/experiments/037-view-workers/)에 있다(`runs.sh`, `views.py`, `plain.py`). +`views.py`는 034의 것에 쓰기 최대 지연의 중앙값과 호스트에 줄 인자(`VIEWS_SERVE_ARGS`)를 더한 것이다. 보기의 길이는 1단계 덕에 +119 때(약 43 ms)보다 짧다. 그래서 견주는 쪽(`--view-workers 0`, 전처럼 연결 스레드가 계산한다)을 같은 빌드로 함께 쟀다. + +**방법.** `pure-serve`(연결 스레드 셋, 저장소는 RAM, 코어 0–2)에 034의 `graph.aup`(노드 2만, 간선 10만, 시드 119, `distance` +보기의 본문이 BFS). 부하 도구(코어 3)가 16연결로 점수를 10초 동안 보낸다. 셋을 번갈아: 쓰기만(writes), 연결 둘이 같은 호스트의 +`distance`를 쉬지 않고 물으며(both), 그 둘이 같은 코어의 다른 호스트에 물으며(apart: CPU만 나눈다). 세 라운드씩 두 번(`runs.sh +tail 1`, `tail 2`), 같은 것을 `--view-workers 0`으로 두 번(`control`). 묻는 쪽은 미리 고른 출발 64곳에서 묻고 모든 답을 모델과 +견준다. 보기의 스레드는 기본(CPU 수: `taskset` 0–2이니 셋)이다. + +| 여섯 라운드의 중앙값 | 쓰기(초당) | 쓰기 p99 | 쓰기 최대 | 보기(초당) | +|---|---:|---:|---:|---:| +| writes | 120,598 | 0.28 ms | 6.0 ms | — | +| both | 50,637 (42.0%) | 3.3 ms | **11.3 ms** (9.7–20.5) | 58.2 (56.4–59.6) | +| apart | 47,688 (39.5%) | 3.5 ms | 11.3 ms (10.2–16.4) | 57.8 | +| both, `--view-workers 0` | 47,431 (38.7%) | 14.6 ms | 75.8 ms (59–131) | 53.2 (35.7–70.5) | +| apart, `--view-workers 0` | 51,301 (41.9%) | 2.0 ms | 9.2 ms | 64.0 | + +- 꼬리의 기준: both의 최대 지연 중앙값이 apart의 1.0배다(기준 2배 이하). `--view-workers 0`이면 8.2배다(119에서 98–188 ms 대 + 6–9 ms였다: 그때의 보기는 1단계 전이라 길었다). +- `--view-workers 0`의 both는 라운드마다 둘 중 하나다. 두 묻는 연결이 다른 연결 스레드에 떨어지면 보기가 초당 70번 나란히 돌고 쓰기가 + 준다. 같은 스레드에 떨어지면 36번 차례로 돌고, 그 스레드에 붙은 쓰기 연결이 보기 하나만큼 기다린다(최대 65–131 ms). 보기의 + 스레드가 있으면 이 갈림이 없다(56–60번). +- 쓰기가 줄어드는 몫은 둘이 같다(42.0% 대 39.5%). 보기의 계산이 코어를 쓰는 만큼이다. 쓰기의 p99가 쓰기만일 때보다 큰 것(3.3 ms)도 + apart와 같다. + +**나란히**(`runs.sh scaling 1`, `scaling 2`): 연결 스레드 하나(`--threads 1`)에 묻는 연결 하나, 둘. 세 라운드씩 두 번. + +| | 하나 | 둘 | 배 | +|---|---:|---:|---:| +| 1 | 37.8 | 73.7 | 1.95 | +| 2 | 37.8 | 73.3 | 1.94 | + +여섯 라운드 모두 하나는 37.8–37.9, 둘은 72.8–74.1이다. 119에서 같은 조건은 1.0배(23.6 대 23.6)였다. + +**짧은 보기**(`runs.sh plain`): 점수판(`benchmarks/http/scores.aup`)에 8연결이 1초 동안 점수를 넣고, 64연결이 `GET /views/total`을 10초 동안. +전(`dde73e4`)과 후(`2fb1da2`)를 번갈아 여섯 쌍, 매번 새 호스트. + +| 중앙값 | 전 | 후 | 바뀜 | +|---|---:|---:|---:| +| 읽기(초당) | 148,867 | 148,530 | −0.2% | + +여섯 쌍 모두 p50 416 µs, p99 640 µs로 같다. + +### 검사 + +- Pure `tests/check.py`의 `server_view_workers`(새 검사): 앱 하나의 호스트(`--apps`, 연결 스레드 하나, 보기의 스레드 둘)에서 + 300만 번 도는 보기를 8연결이 쉬지 않고 묻는 동안, 앱의 모듈을 그 보기의 자리에 다른 보기(`other = 7`)가 있고 값이 열 배인 + 모듈로 바꾸고(SIGHUP), 이어서 앱을 뺀다. 모든 답이 옛 모듈의 값, 새 모듈의 값, 503 `stopped`, 404 가운데 하나다(섞인 답은 + `7`로 보였을 것이다). 그 보기의 스트림이 같은 스트림에서 새 모듈의 값을 받고, 앱이 빠지면 끝난다. 값이 오기 전에 닫은 스트림 + 열 개가 아무것도 남기지 않는다(멈출 때 구독자 0). `--view-workers 0`이면 보기의 스레드가 없고 같은 답이다. +- `server_view_bodies`(64연결이 동시에 묻는 `distance` 1,280개가 모두 모델과 같다)와 `server_push`(계산하는 보기를 미는 것 포함)가 + 이제 보기의 스레드를 거쳐 그대로 초록이다. +- Pure의 `make check`, aup와 Vega의 모든 검사가 초록이다. + +## 판정 + +- **020의 2단계는 들어간다.** 세 통과 조건(꼬리 2배 이하: 1.0배, 나란히 1.8배 이상: 1.95배, 짧은 보기 3% 안: −0.2%)을 모두 채웠다. +- 119가 남긴 두 가지(연결 스레드가 막는 꼬리, 연결의 자리에 따라 갈리는 보기의 처리량)가 없어졌다. + +## 다음 + +- 019의 미는 보기도 보기의 스레드를 거친다(검사로만 봤다: 계산하는 보기의 스트림, 값이 오기 전에 닫힌 스트림). 구독자가 많은 + 계산하는 보기의 신선도는 재지 않았다. +- 보기의 스레드가 다 바쁠 때 넘긴 일은 줄을 선다. 그 줄의 한도는 앱의 `queue=N`이고, 한 앱의 호스트에서는 연결 수다. 줄을 서는 + 동안의 지연을 다른 보기와 나누는 것(앱마다 공평하게)은 앱이 여럿일 때 잰다. |
