64 메가바이트의 절벽

raytracer 가 어셈블되게 되자, 물음은 boxing 이 무엇을 치르게 하는가가 되었다. 측정: 96×54 렌더는 결코 해제하지 않는 bump 알로케이터에서 26 메가바이트를 확보한다 —— 픽셀당 약 5 킬로바이트, 텍스트가 15 킬로바이트인 이미지를 위해. 같은 프로그램을 320×180 으로 하면 세금은 backend 의 고정 64 메가바이트 선형 메모리를 넘는다. 렌더는 프레임의 3 분의 1 에서 trap 한다. out of bounds, 정확히 마지막 페이지에서. 도중에 checksum 자체도 바꿔야 했다 —— CRC-32 는 0xFFFFFFFF 와 논리 시프트를 요구하고, 어느 쪽도 32-bit 부호 있는 int 로는 표현할 수 없다. backend 의 정수 폭이 설계에 손을 뻗어 알고리즘을 고른 것이다. 절벽의 수정은 알려져 있고, 스코프되어 있고, 보류되었다. alloc 은 79 곳에 인라인되어 있고, 중앙 집약은 진짜 일이며, 그것을 요구하는 실제 프로그램은 아직 없다. 절벽이 앉은 숫자를 적어 두는 것은 절벽이 없는 척하는 것보다 가치 있다.

merewasmmemoryperformancelanguage-design

선언은 고쳐졌고 raytracer 는 세 backend 에서 하나의 checksum 과 한 장의 이미지와 함께 달렸다. 올바름에는 답이 나왔다. probe 의 원래 물음은 아직 열려 있었다. 모든 float 를 box 하는 것은 실제로 무엇을 치르게 하는가. 모듈을 달리게 하고 끝난 뒤 알로케이터의 bump 포인터를 읽는 작은 하니스가 숫자를 냈다. 96×54 렌더 —— 5 천 픽셀, 출력 텍스트는 15 킬로바이트 —— 는 26 메가바이트를 확보했다. 픽셀당 5 킬로바이트의 heap, 그 어느 것도 해제되지 않는다. bump 알로케이터는 앞으로만 나아가기 때문이다. 모든 곱셈, 모든 내적, 모든 중간 벡터의 각 성분이 8 바이트와 정렬로 잘려 나와서는 버려진다. C backend 는 같은 이미지를 몇 메가바이트의 프로세스로 렌더링한다. Wasm 에서는 산술 자체가 확보인 것이다.

절벽에는 번지가 있다

다음으로 같은 프로그램을 320×180 으로. 세금은 픽셀 수에 비례한다. 11 배의 면적은 대략 290 메가바이트를 요구하고, backend 의 선형 메모리는 고정 1024 페이지 —— 64 메가바이트 —— 로 선언되어 있으며, 어디에도 memory.grow 를 부르는 것은 없다. 렌더는 프레임의 3 분의 1 에서 trap 한다. out of bounds, bump 포인터는 정확히 67,108,864 에 멈춰서. “Wasm 의 메모리 성장” 이라는 보류 항목은 몇 달이나 추상적인 걱정이었다. 이제 번지가 있다. 96×54 의 float 프로그램은 동작한다. 320×180 의 것은 죽는다. 절벽의 가장자리는 적어 둘 수 있는 숫자다.

정수 폭이 알고리즘을 고를 때

또 하나의 발견은 옆에서 왔다. 픽셀의 checksum 은 CRC-32 예정이었다. 바이너리 계열 probe 가 전부 써 온 checksum 이다 —— 그리고 Wasm backend 는 상수 0xFFFFFFFF 를 컴파일 시에 거부했다. 바로 이 용도를 위해 두 달 전에 만들어진 pointed error 로. 리터럴이 32-bit 부호 있는 int 에 들어가지 않는 것이다. 게다가 상수만이 아니다. CRC 는 논리 우시프트를 요구하고, backend 의 부호 있는 int 의 시프트는 산술 시프트다. 정직한 응답은 CRC 를 비틀어 맞추는 것이 아니라 알고리즘을 바꾸는 것이었다. Adler 계열 checksum, mod 65521 의 달리는 합 둘, 모든 중간값이 31 비트에 여유 있게 들어가고, 63-bit 인터프리터에서도 64-bit C 에서도 32-bit Wasm 에서도 동일. 이식성에 관한 작고 구체적인 교훈이다. backend 의 정수 폭은 값을 제한할 뿐이 아니다 —— 설계에까지 손을 뻗어 알고리즘을 고른다.

숫자를 붙여 보류하다

명백한 다음 수는 절벽을 고치는 것일 테다. bump 알로케이터에게 메모리를 성장시키는 법을 가르친다. 그것을 스코프해 보니 왜 이미 두 번 보류되었는지 알 수 있었다 —— alloc 은 함수가 아니라 이디엄이고, emitter 와 손으로 쓴 runtime 템플릿에 걸친 79 곳에 인라인되어 있다. robust 한 수정은 전부를 하나의 확보 루틴 —— 검사하고, 성장시키고, bump 하는 —— 으로 중앙 집약하는 것이다. 두 편 전의 이름공간화와 같은 형태로, 균일한 기계가 흩어진 반복을 대체하고 테스트 스위트가 이행을 검증한다. 그것은 진짜의, 범위가 잘리는 일이다 —— 그리고 그것을 요구하는 실제 프로그램은 아직 없다. 보류 파일에 측정값을 붙여 기록한 정직한 자세는 이렇다. Wasm 에서는 float 가 짙은 계산은 작게. 절벽은 64 메가바이트에 있다. 그것을 넘는 성장은 요구하는 프로그램을 기다리는 알려진 리팩터다. 그리고 세금 자체 —— 픽셀당 5 킬로바이트 —— 는 메모리가 아무리 성장해도 남는다. 그쪽의 진짜 수정은 float 를 형 있는 local 로 unbox 하는 것이고, 그것은 다른 날의, 다른 큰 한 편이다. 두 개의 숫자와 스코프된 계획으로 끝나는 probe 는 일을 다한 probe 다.

← Back to Mere: 언어를 만들다