diff options
Diffstat (limited to 'docs/research')
| -rw-r--r-- | docs/research/140-spec-suite.md | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/docs/research/140-spec-suite.md b/docs/research/140-spec-suite.md index 3ddb709..9cbe5c2 100644 --- a/docs/research/140-spec-suite.md +++ b/docs/research/140-spec-suite.md @@ -51,11 +51,11 @@ | 2 | SHA-256(FIPS 180-4) | 해시 | 32비트 낱말, 회전, xor | NIST CAVP의 SHA 벡터 | 우회로만 될 것으로 보인다(써 보지 않음) | 썼다: NIST 벡터를 세 실행 길에서 지난다(1단계) | | 3 | inflate(RFC 1951) | 압축 | 비트 읽기, 허프만 표, 뒤 참조 | zlib로 압축한 말뭉치를 풀어 원본과 비교 | 못 쓴다(바이트, 비트) | 썼다: zlib 스트림 640개, 손상 240개가 파이썬 참조와 같다. 우회 없음, 줄 1.5배, C의 102배(아래) | | 4 | JSON(RFC 8259) → 트리와 질의 | 깊이를 모르는 데이터 | 글자 읽기, 중첩, 재귀, 갈래 | JSONTestSuite | 못 쓴다(글자, 중첩, 재귀, 갈래) | 썼다: JSONTestSuite와 무작위 문서가 파이썬과 같다(2a–2c) | -| 5 | UTF-8과 줄 나누기(UAX #14) | 텍스트 | 바이트, 코드 포인트, 속성 표 | Unicode의 `LineBreakTest.txt` | 못 쓴다(글자) | 썼다: LineBreakTest.txt 16,672줄 모두와 무작위 2,000줄이 맞다. 줄 1.8배, C의 199배(아래) | +| 5 | UTF-8과 줄 나누기(UAX #14) | 텍스트 | 바이트, 코드 포인트, 속성 표 | Unicode의 `LineBreakTest.txt` | 못 쓴다(글자) | 썼다: LineBreakTest.txt 16,672줄 모두와 무작위 2,000줄이 맞다. 줄 1.7배(마찰을 걷어 낸 뒤), C의 199배(아래) | | 6 | 관계 질의, 그래프 탐색 | 데이터 모델 | 리스트, 키, 접기, 이벤트의 리스트 | TPC-C, 은행 질의, 파이썬 모델 | 된다(기준선: [092](092-tpcc.md), 040의 은행 질의, aup `routes.aup`) | 된다. TPC-C가 SQLite와 오차 없이 같다(5단계) | | 7 | 텍스트 편집 | UI 개념 | text, 커서 | 편집기의 참조 모델 대조(aup `make check`) | 된다 | 된다 | -| 8 | 상자 배치(flex 같은) | UI 개념 | 중첩, 재귀 | 기존 배치 구현(Yoga, Taffy)의 결과와 대조 | 못 쓴다(중첩, 재귀) | 썼다(Flexbox의 부분집합): 무작위 트리 2,000개가 Taffy와 0.01 안, 파이썬 참조와 비트까지 같다. 줄 2.1배, Taffy의 7.4배(아래) | -| 9 | HTTP/1.1 요청을 패킷마다(RFC 9112) | 스트림의 상태 기계 | 바이트, 이벤트를 넘는 상태 | 경계를 아무 데서나 자른 요청 모음 | 못 쓴다(바이트). 지금은 `serve/`의 C다 | 썼다: 스트림 200개를 어디서 잘라도 h11과 같다. 우회 하나(리스트 값의 대입), 줄 1.9배, C의 83배(아래) | +| 8 | 상자 배치(flex 같은) | UI 개념 | 중첩, 재귀 | 기존 배치 구현(Yoga, Taffy)의 결과와 대조 | 못 쓴다(중첩, 재귀) | 썼다(Flexbox의 부분집합): 무작위 트리 2,000개가 Taffy와 0.01 안, 파이썬 참조와 비트까지 같다. 줄 2.0배(마찰을 걷어 낸 뒤), Taffy의 7.4배(아래) | +| 9 | HTTP/1.1 요청을 패킷마다(RFC 9112) | 스트림의 상태 기계 | 바이트, 이벤트를 넘는 상태 | 경계를 아무 데서나 자른 요청 모음 | 못 쓴다(바이트). 지금은 `serve/`의 C다 | 썼다: 스트림 200개를 어디서 잘라도 h11과 같다. 우회 없음(리스트 값의 대입을 aup에 넣었다), 줄 1.8배, C의 83배(아래) | | 10 | 재시도, 물러서기, 시간 제한 | 시간 | 시각, 한 번의 타이머 | 시각을 준 시뮬레이션 | 우회(주기 틱 `every`와 `now`) | 썼다(RFC 6298): 사건 241,612개가 같은 규칙의 모델과 같다. 우회 하나(주기 틱: 10 ms면 타임아웃 하나에 틱 2,796개), 줄 1.9배(아래) | | 11 | X25519, ChaCha20-Poly1305 | 상수 시간 암호 | 데이터에 따라 달라지지 않는 시간 | RFC 7748, RFC 8439의 벡터 | aup 밖(설계상, 아래) | 그대로(설계상 aup 밖) | @@ -921,6 +921,44 @@ min과 max가 남는다. Flexbox의 어려운 반은 크기가 아래에서 위로 올라오는 쪽인데, 이 부분집합은 크기가 위에서 오는 반만 잰다. 그 반은 aup로 새 명령 없이 쓰이고, Taffy와 같다. +## aup의 마찰을 걷어 내고 다시 잼 (2026-10-19) + +열한 명세를 쓰며 적은 마찰 가운데 코어를 바꾸지 않고 풀리는 것을 aup에서 풀었다. 새 명령은 없다. 바꾸기 전에 컴파일되던 aup 소스 +81개(aup, Pure, Vega)의 모듈은 모두 바이트까지 같다. +- **리스트의 let 여럿을 한 줄에.** `let codes, cls, eff: list of number`. 이름마다 그 레코드의 리스트 하나다(UAX #14의 마찰 3, 배치의 + 마찰 4). +- **대상 여럿.** `boxes[k].x, boxes[k].y = at, top`처럼 대상에 항목의 필드와 위치가 섞여도 된다(배치의 마찰 1). 값을 먼저 모두 셈하고, + 대상마다 왼쪽부터 준다(파이썬과 같다). 값이 앞 대상이 바꾸는 것을 읽을 수 없으면 숨은 let 없이 곧바로 준다. 대상의 이름, fn의 부름, + 바뀌는 리스트의 인덱스나 for의 항목을 읽는 값이 있으면 숨은 let을 거친다. 처음에는 늘 숨은 let을 거쳐 배치의 명령이 2.1% + 늘었다(노드당 1,525.9). 곧은 길을 넣은 뒤 1,492.8이고, 손으로 쓴 것은 1,493.9다. +- **리스트에 리스트 값.** `trailers, j = fields(d, c + 2)`, `kept = ts`, `boxes = []`. 저장되는 리스트에도 된다(HTTP의 남은 우회, 배치의 + 마찰 2). 비우고 채우는 고리는 손으로 쓴 것과 같은 명령이다. +- **`abs(x)`와 `tick.period`.** RFC 6298의 마찰 1과 2다. G를 `every`와 fn에 두 번 쓰지 않는다. +- **수를 만나는 16진은 수.** `base == 0x2010`(UAX #14의 마찰 1). 2^53을 넘으면 거절한다. 따로 서거나 i64를 만나면 예전처럼 i64다. +- **쓰다가 찾은 결함.** 리스트의 let을 셋 이상 한 줄에 쓰면 문장이 고리가 되어 컴파일러가 끝나지 않았다(줄 나누기의 아홉 리스트를 + 두 줄로 쓰다 찾았다). aup의 `frictions` 시험이 이제 넷을 쓴다. + +| 명세 | 줄(닫는 괄호) 전 → 뒤 | 파이썬 | 바꾼 것 | 단위당 명령 전 → 뒤 | 단위당 ns 전 → 뒤 | +|---|---|---|---|---|---| +| inflate | 121(15) → 120(15) | 81 | 리스트의 let 둘을 한 줄에 | 191.2(모듈이 같다) | 같다 | +| DNS | 106(18) → 106(18) | 72 | `records = []`, `0xc000 + s.at` | 49.9 → 49.8 | 221.0 → 220.0 | +| HTTP/1.1 | 148(21) → 146(21) | 79 | `trailers, j = fields(…)` | 61.5 → 61.6 | 270.6 → 270.6 | +| UAX #14 | 176(19) → 169(19) | 99 | 리스트의 let 아홉을 두 줄에, `0x2010`, `0x25CC` | 1,774(모듈이 같다) | 같다 | +| RFC 6298 | 56(11) → 56(11) | 30 | `abs(srtt - r)`, `tick.period` | 확인 192.7 → 191.7 | — | +| 상자 배치 | 116(17) → 110(17) | 54 | 리스트의 let 넷을 한 줄에, 상자와 뿌리의 대상 묶음, `boxes = []` | 1,493.9 → 1,492.8 | 4,756 → 4,647 | + +- **줄.** 파이썬 대비 1.47–2.15배에서 1.47–2.04배로 줄었다. 같아진 것도 있다: DNS와 RFC 6298은 줄은 같고 읽기만 나아졌다(`while` + 한 줄이 `records = []`, `max(srtt - r, r - srtt)`가 `abs(srtt - r)`, G가 한 곳). +- **명령과 시간.** 모듈이 바뀐 넷의 명령은 ±0.2% 안이다. 배치의 시간 −2.3%는 명령이 같으므로 자리 잡음 범위로 본다(세 쌍을 번갈아 + 잰 중앙값). +- **세 실행 길.** 여섯 명세의 검사가 새 앱으로 모두 지난다: dnspython의 메시지 400개와 손상 300개, h11의 스트림 200개(모든 자름), + RFC 6298의 사건 241,612개, 배치의 트리 2,000개(Taffy의 0.01 안, 참조와 비트까지). inflate와 UAX #14는 모듈이 같다. Pure의 + `module_specs` 아홉이 지난다. +- **남은 마찰.** + - 코어의 것: 보기에서 블록 fn 부르기(DNS), 레코드 하나인 상태, 커서 자리의 글자. + - aup에 두는 것: 축을 필드 번호로 고르기(배치의 마찰 3), `number`나 `send` 같은 이름. 이름은 타입과 말의 자리를 지키려고 그대로 둔다. +- 원본: `2026-10-19-frictions.jsonl`(검사, 전과 뒤의 명령과 시간, 줄). aup의 설계 002 "140의 마찰을 걷어 냄". + ## 착수 기준 (다음 일) - **바꿀 결정.** 계산의 핵을 설계한다(027). 위 표의 여덟 후보 가운데 무엇을 어떤 모양으로 받을지 정한다. |
