알고리즘: typeshade/algorithms
typeshade/algorithms는 공용 모듈입니다. "use typeshade"로 쓴 커널 함수를 패키지의 하위 경로로 내보낸다(규칙 11.20). 배열에 대한 복사, 채우기, 맵, 리덕션, 스캔, 압축, 히스토그램이 들어 있습니다. 각 함수는 WebGPU, WebGL2, CPU tier에서 돌며, 어느 쪽에서든 CPU 오라클과 같은 비트를 냅니다. fuse 스코프 안에서는 사실이 허용하는 만큼 주변 호출과 합쳐집니다.
1. 호스트 인터페이스
호스트 코드는 다른 패키지처럼 이 하위 경로를 가져오고, 각 함수를 Resident 배열 위에서 부릅니다. 따로 부를 수도 있고 fuse 본문 안에서 부를 수도 있습니다. 각 함수는 출력의 모든 원소를 쓰므로, 디바이스 풀에서 받은 배열을 따로 초기화할 필요가 없습니다. 예외는 histogram 하나입니다. 이 함수는 받은 칸에 개수를 더하므로, 호출하는 쪽이 칸을 먼저 초기화합니다.
import { fuse } from 'typeshade/fuse';import { fill, add, relu, sumAxis, exclusiveScan, compact } from 'typeshade/algorithms';import { fillUniform } from 'typeshade/random';
await fuse(() => { fill(t, 1); // t[i] = 1 add(u, t, b); // u[i] = t[i] + b[i] relu(v, u); // v[i] = max(u[i], 0): one dispatch with the two before it sumAxis(rows, v, columns, 1); // a group of its own: it reads v at another index});
await fuse(() => { fillUniform(noise, 12345); exclusiveScan(offsets, flags, sums); // sums: the caller's scratch compact(kept, rows, flags, offsets);});2. 함수 목록
행에 따로 적지 않은 배열 매개변수는 array<f32>이입니다.
| 묶음 | 함수 | 하는 일 |
|---|---|---|
| 복사와 채우기 | copy(out, x), fill(out, value), sequence(out, start, step) | i에서 도는 루프 하나입니다. sequence는 start + f32(i) * step을 씁니다. |
| 이항 맵 | (out, a, b) 형태의 add, sub, mul, div와 scale(out, x, k) | i의 루프 하나. |
| 단항 맵 | (out, x) 형태의 abs, neg, sqrt, rsqrt, exp, log, expm1, log1p, floor, ceil, round, sign, sin, cos, tan, tanh, sigmoid, relu와 clip(out, x, lo, hi) | i에서 도는 루프 하나입니다. 셰이더 모듈에서는 absMap처럼 <op>Map이라는 이름을 씁니다. 커널 함수는 내장 함수의 이름을 가질 수 없기 때문입니다. |
| 전체 리덕션 | sum(x), max(x), min(x)이며, 각각 f32를 돌려줍니다 | 모든 tier에서 같은 트리 순서로 접는다(규칙 7.2). 셰이더 모듈에서는 sum, maxAll, minAll이다. |
| 축 리덕션 | (out, x, axis, inner) 형태의 sumAxis, meanAxis, prodAxis, maxAxis, minAxis, argMaxAxis, argMinAxis | x를 [outer, axis, inner]로 읽습니다. out의 각 원소는 오름차순으로 차례로 접은 값입니다. |
| 스캔 | array<u32>에 대한 inclusiveScan(out, x, sums), exclusiveScan(out, x, sums) | 커널 함수 하나 안의 루프 두 개입니다. sums는 호출하는 쪽의 스크래치이며, 원소가 하나 이상이고 x 길이의 제곱근 정도면 됩니다. |
| 압축 | compact(out, x, flags, offsets) | 플래그가 1인 원소를 원래 순서대로 모읍니다. offsets는 flags의 배타적 스캔입니다. |
| 히스토그램 | histogram(bins, x, lo, hi) | [lo, hi)를 같은 너비로 나눈 각 칸에 드는 x의 개수를 bins에 더합니다. WebGPU에서는 더하기마다 원자 연산입니다. |
3. 호출이 합쳐지는 방식
모든 맵은 out의 i에 쓰고 입력도 i에서 읽습니다. 그래서 맵의 체인은 디스패치 하나가 되고, 전체 리덕션은 체인의 마지막 호출로 합류합니다. 축 리덕션, 스캔, 압축은 입력을 다른 인덱스에서 읽습니다. 그래서 그 입력을 쓴 호출 뒤에서는 저마다 새 그룹을 시작합니다. 예제의 첫 스코프에서는 fill, add, relu가 디스패치 하나로, sumAxis가 두 번째 디스패치로 실행되며, 둘은 제출 하나에 담깁니다.
4. 함수가 실행되는 곳
컴파일러의 차등 게이트는 모든 함수를 WebGPU와 WebGL2에서 불러 CPU 오라클과 비교합니다. 결정성 보고서에 행이 없는 함수는 비트 단위로 같아야 하고, exp나 sin처럼 행이 있는 함수는 정해진 범위 안에 들어야 합니다. WebGL2는 전체 리덕션 세 개, 스캔 두 개, compact, histogram을 거부합니다. 그래서 이 호출들은 선택된 소유자의 prefer 정책에서 다음 tier로 넘어간다(규칙 11.8).
5. 디바이스 인터페이스
"use typeshade" 파일도 typeshade/algorithms에서 가져올 수 있습니다. 이 하위 경로는 typeshade 조건에서 셰이더 모듈을 가리킵니다. 그 내보내기는 커널 함수이고, 커널 함수는 다른 함수가 부르지 않습니다. 그래서 이번 버전에서 셰이더 파일이 이 모듈에서 부를 함수는 없습니다. 커널이 자기 워크그룹 메모리 위에서 조합하는 헬퍼는 다음에 나옵니다.
6. 아직 없는 것
정렬, 분할, 구간별 리덕션, reduceByKey, 최근접 이웃 탐색, 행렬 곱, f64 선형대수, 워크그룹 메모리 스캔은 다음에 나옵니다.