cublas.bend

bend-blas-lapack@0.0.0.1 · 64 lines · 12 definitions

1# bend-blas: cuBLAS on Array<F32>, one def per routine, plus device
2# buffers. Generated by gen/effs.py: edit the table there, not this file.
3#
4# The same conventions as blas.bend. cuBLAS is opened at runtime with
5# dlopen (libcudart, libcublas), so this file builds anywhere; on a
6# machine without CUDA every routine answers Fail{(1, ..)}, and
7# Cublas.available answers False. A device buffer is uploaded once
8# (Cublas.upload), referenced by its U32 id, never consumed, and freed
9# with Cublas.free; Cublas.sgemm_w reads one as its right operand, so a
10# model's weights cross the bus once. On the interpreter the JS twins
11# run on the host: plain loops, correct and slow. Not yet run on an
12# NVIDIA machine: the C is checked against the cuBLAS signatures only.
13import Base
14
15# True when cuBLAS opens on this machine: the answer of every other routine is Fail{(1, ..)} otherwise. Never fails.
16def Cublas.available() -> IO(Result<&1, &1, U32 & String, Bool>):
17  import "./effs/cublas_available.c"
18  import "./effs/cublas_available.js"
19
20def Cublas.available.try() -> IO(Bool):
21  IO.try(Bool, Cublas.available())
22
23# The first n floats of an array copied to the device; answers the buffer id. The array is consumed.
24def Cublas.upload(n: U32, a: Array<F32>) -> IO(Result<&1, &1, U32 & String, U32>):
25  import "./effs/cublas_upload.c"
26  import "./effs/cublas_upload.js"
27
28def Cublas.upload.try(n: U32, a: Array<F32>) -> IO(U32):
29  IO.try(U32, Cublas.upload(n, a))
30
31# The n floats of a device buffer back in a fresh array; the buffer stays.
32def Cublas.download(id: U32) -> IO(Result<&1, &1, U32 & String, Array<F32>>):
33  import "./effs/cublas_download.c"
34  import "./effs/cublas_download.js"
35
36def Cublas.download.try(id: U32) -> IO(Array<F32>):
37  IO.try(Array<F32>, Cublas.download(id))
38
39# Frees a device buffer; its id is dead after.
40def Cublas.free(id: U32) -> IO(Result<&1, &1, U32 & String, Unit>):
41  import "./effs/cublas_free.c"
42  import "./effs/cublas_free.js"
43
44def Cublas.free.try(id: U32) -> IO(Unit):
45  IO.try(Unit, Cublas.free(id))
46
47# C = alpha op(A) op(B) + beta C on the GPU, the operands copied to the
48# device for the call and the result back; the same arguments as
49# Blas.sgemm.
50def Cublas.sgemm(ta: U32, tb: U32, m: U32, n: U32, k: U32, alpha: F32, a: Array<F32>, b: Array<F32>, beta: F32, c: Array<F32>) -> IO(Result<&1, &1, U32 & String, Array<F32>>):
51  import "./effs/cublas_sgemm.c"
52  import "./effs/cublas_sgemm.js"
53
54def Cublas.sgemm.try(ta: U32, tb: U32, m: U32, n: U32, k: U32, alpha: F32, a: Array<F32>, b: Array<F32>, beta: F32, c: Array<F32>) -> IO(Array<F32>):
55  IO.try(Array<F32>, Cublas.sgemm(ta, tb, m, n, k, alpha, a, b, beta, c))
56
57# Cublas.sgemm with the right operand a device buffer (uploaded once with
58# Cublas.upload, never consumed): the shape of a model's weights.
59def Cublas.sgemm_w(ta: U32, tb: U32, m: U32, n: U32, k: U32, alpha: F32, a: Array<F32>, b: U32, beta: F32, c: Array<F32>) -> IO(Result<&1, &1, U32 & String, Array<F32>>):
60  import "./effs/cublas_sgemm_w.c"
61  import "./effs/cublas_sgemm_w.js"
62
63def Cublas.sgemm_w.try(ta: U32, tb: U32, m: U32, n: U32, k: U32, alpha: F32, a: Array<F32>, b: U32, beta: F32, c: Array<F32>) -> IO(Array<F32>):
64  IO.try(Array<F32>, Cublas.sgemm_w(ta, tb, m, n, k, alpha, a, b, beta, c))