Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions docs/content/gosl.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
**Gosl** allows you to write Go programs that run on [[GPU]] hardware, by transpiling Go into the WGSL shader language used by [WebGPU](https://www.w3.org/TR/webgpu/), thereby establishing the _Go shader language_.
+++
Name = "GoSL"
+++

Gosl uses the [core gpu](https://github.com/cogentcore/core/tree/main/gpu) compute shader system, and operates within the overall [[Goal]] framework of an augmented version of the Go language.
**GoSL** allows you to write Go programs that run on [[GPU]] hardware, by transpiling Go into the WGSL shader language used by [WebGPU](https://www.w3.org/TR/webgpu/), thereby establishing the _Go shader language_.

GoSL uses the [core gpu](https://github.com/cogentcore/core/tree/main/gpu) compute shader system, and operates within the overall [[Goal]] framework of an augmented version of the Go language.

The relevant regions of Go code to be run on the GPU are tagged using the `//gosl:start` and `//gosl:end` comment directives, and this code must only use basic expressions and concrete types that will compile correctly in a GPU shader (see [[#Restrictions]] below). Method functions and pass-by-reference pointer arguments to `struct` types are supported and incur no additional compute cost due to inlining (see notes below for more detail).

Expand All @@ -27,6 +31,8 @@ There are two key elements for GPU-enabled code:

2. [[#Global variables]] on which the kernel functions _exclusively_ operate: all relevant data must be specifically copied from the CPU to the GPU and back. As explained in the [[GPU]] docs, each GPU compute shader is effectively a _standalone_ program operating on these global variables. To replicate this environment on the CPU, so the code works in both contexts, we need to make these variables global in the CPU (Go) environment as well.

**IMPORTANT:** All tensor variables must be sent to the GPU at least once before running, because the generated code does not know the size of the tensor until this is done! This is true even if a variable is just a results variable that does not logically need to be uploaded to the GPU -- the overhead at startup for a single such transfer is not worth the extra complexity of creating the necessary alternative init code.

`gosl` generates a file named `gosl.go` in your package directory that initializes the GPU with all of the global variables, and functions for running the kernels and syncing the gobal variable data back and forth between the CPu and GPU.

## Kernels
Expand All @@ -35,11 +41,18 @@ Each distinct compute kernel must be tagged with a `//gosl:kernel` comment direc
```go
// Compute does the main computation.
func Compute(i uint32) { //gosl:kernel
if i >= Params[0].DataLen { // note: essential to bounds check b/c i in 64 blocks
return
}
Params[0].IntegFromRaw(int(i))
}
```

The kernel functions receive a `uint32` index argument, and use this to index into the global variables containing the relevant data. Typically the kernel code itself just calls other relevant function(s) using the index, as in the above example. Critically, _all_ of the data that a kernel function ultimately depends on must be contained with the global variables, and these variables must have been sync'd up to the GPU from the CPU prior to running the kernel (more on this below).
The kernel functions receive a `uint32` index argument, and use this to index into the global variables containing the relevant data.

**IMPORTANT:** the dispatch of kernels on the GPU is in blocks of 64 processors, so i will exceed the number that you pass into the `Run` function! It is essential to check bounds in every kernel.

Typically the kernel code itself just calls other relevant function(s) using the index, as in the above example. Critically, _all_ of the data that a kernel function ultimately depends on must be contained with the global variables, and these variables must have been sync'd up to the GPU from the CPU prior to running the kernel (more on this below).

In the CPU mode, the kernel is effectively run in a `for` loop like this:
```go
Expand Down Expand Up @@ -68,7 +81,7 @@ var (
```

All such variables must be either:
1. A `slice` of GPU-alignment compatible `struct` types, such as `ParamStruct` in the above example. In general such structs should be marked as `//gosl:read-only` due to various challenges associated with writing to structs, detailed below.
1. A `slice` of GPU-alignment compatible `struct` types, such as `ParamStruct` in the above example. In general such structs should be marked as `//gosl:read-only` due to various challenges associated with writing to structs, detailed below. Due to lack of package-relative naming in the final WGSL file, any struct type defined in a sub package will show up unqualified in the generated `gosl.go` file, so a type alias is required to allow the resulting Go file to build properly.
2. A `tensor` of a GPU-compatible elemental data type (`float32`, `uint32`, or `int32`), with the number of dimensions indicated by the `//gosl:dims <n>` tag as shown above. This is the preferred type for writable data.

You can also just declare a slice of elemental GPU-compatible data values such as `float32`, but it is generally preferable to use the tensor instead, because it has built-in support for higher-dimensional indexing in a way that is transparent between CPU and GPU.
Expand Down Expand Up @@ -232,7 +245,7 @@ var<storage, read_write> PathGBuf: array<atomic<i32>>;
atomicAdd(&PathGBuf[idx], val);
```

This also unfortunately has the side-effect that you cannot do _non-atomic_ operations on atomic variables, as discussed extensively here: https://github.com/gpuweb/gpuweb/issues/2377 Gosl automatically detects the use of atomic functions on GPU variables, and tags them as atomic.
This also unfortunately has the side-effect that you cannot do _non-atomic_ operations on atomic variables, as discussed extensively here: https://github.com/gpuweb/gpuweb/issues/2377 GoSL automatically detects the use of atomic functions on GPU variables, and tags them as atomic.

## Random numbers: slrand

Expand All @@ -244,9 +257,13 @@ See [[doc:gosl/slrand]] for a shader-optimized random number generation package,
//gosl:end mycode
```

## WGSL vector variables from math32.Vector2 etc: not yet

WGSL supports variables like `vec4<f32>` which is equivalent to `math32.Vector4`. Unfortunately, it would be difficult to have simultaneous, transparent support for both of these types across Go and WGSL, requiring rewriting expressions on the WGSL side. It is possible, but would take a fair amount of work, and is not yet planned.

## Performance

With sufficiently large N, and ignoring the data copying setup time, around ~80x speedup is typical on a Macbook Pro with M1 processor. The `rand` example produces a 175x speedup!

## Gosl pages


4 changes: 2 additions & 2 deletions docs/content/math.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fmt.Println("d:", d)

See [[tensor math#Alignment of shapes]] for more details on [[tensor math]] operations, using the NumPy [broadcasting](https://numpy.org/doc/stable/user/basics.broadcasting.html) logic.

### Tensorfs
### TensorFS

In an interactive Goal shell (which we simulate here in the docs), variables in math mode are automatically saved to the [[tensorfs]] virtual data filesystem:

Expand Down Expand Up @@ -371,7 +371,7 @@ todo: huge amount of work needed to support complex numbers throughout!
| . | . |`np.fft.ifft(a)` | inverse Fourier transform of `a` |
| . | . |`signal.resample(x, np.ceil(len(x)/q))` | downsample with low-pass filtering |

### Tensorfs
### TensorFS

The [[tensorfs]] data filesystem provides a global filesystem-like workspace for storing tensor data, and [[Goal]] has special commands and functions to facilitate interacting with it.

Expand Down
4 changes: 2 additions & 2 deletions docs/content/tensorfs.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
+++
Categories = ["Tensorfs"]
Name = "TensorFS"
+++

**tensorfs** provides a virtual filesystem for [[tensor]] data, which can be accessed for example in [[Goal]] [[math]] mode expressions, like the variable storage system in [IPython / Jupyter](https://ipython.readthedocs.io/en/stable/interactive/tutorial.html), with the advantage that the hierarchical structure of a filesystem allows data to be organized in more intuitive and effective ways. For example, data at different time scales can be put into different directories, or multiple different statistics computed on a given set of data can be put into a subdirectory. [[stats#Groups]] creates pivot-table style groups of values as directories, for example.
**TensorFS** provides a virtual filesystem for [[tensor]] data, which can be accessed for example in [[Goal]] [[math]] mode expressions, like the variable storage system in [IPython / Jupyter](https://ipython.readthedocs.io/en/stable/interactive/tutorial.html), with the advantage that the hierarchical structure of a filesystem allows data to be organized in more intuitive and effective ways. For example, data at different time scales can be put into different directories, or multiple different statistics computed on a given set of data can be put into a subdirectory. [[stats#Groups]] creates pivot-table style groups of values as directories, for example.

`tensorfs` implements the Go [fs](https://pkg.go.dev/io/fs) interface, and can be accessed using fs-general tools, including the cogent core `filetree` and the [[Goal]] shell.

Expand Down
1 change: 1 addition & 0 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func main() {
b := core.NewBody("Cogent Lab")
ct := content.NewContent(b).SetContent(econtent)
ctx := ct.Context
content.OfflineURL = "https://cogentcore.org/lab"
ctx.AddWikilinkHandler(htmlcore.GoDocWikilink("doc", "cogentcore.org/lab"))
b.AddTopBar(func(bar *core.Frame) {
tb := core.NewToolbar(bar)
Expand Down
8 changes: 8 additions & 0 deletions examples/baremetal/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,11 @@ func (bm *BareMetal) UpdateJobs() (nrun, nfinished int, err error) {
bm.saveState()
return
}

// RecoverJob reinstates job information so files can be recovered etc.
func (bm *BareMetal) RecoverJob(job *Job) (*Job, error) {
bm.Lock()
defer bm.Unlock()

return bm.recoverJob(job)
}
31 changes: 18 additions & 13 deletions examples/baremetal/baremetal/baremetal.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/baremetal/baremetal/baremetal.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ service BareMetal {
rpc CancelJobs (JobIDList) returns (Error);
rpc FetchResults (JobIDList) returns (JobList);
rpc UpdateJobs (google.protobuf.Empty) returns (google.protobuf.Empty);
rpc RecoverJob (Job) returns (Job);
}

// Submission is a job submission.
Expand Down
38 changes: 38 additions & 0 deletions examples/baremetal/baremetal/baremetal_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions examples/baremetal/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,17 @@ func (cl *Client) FetchResults(resultsGlob string, ids ...int) ([]*Job, error) {
func (cl *Client) UpdateJobs() {
return
}

// RecoverJob recovers a job which has been lost somehow.
// It just adds the given job to the job table.
func (cl *Client) RecoverJob(job *Job) (*Job, error) {
ctx, cancel := context.WithTimeout(context.Background(), cl.Timeout)
defer cancel()

pjob := JobToPB(job)
rjob, err := cl.client.RecoverJob(ctx, pjob)
if err != nil {
return nil, errors.Log(fmt.Errorf("RecoverJob failed: %v", err))
}
return JobFromPB(rjob), nil
}
8 changes: 8 additions & 0 deletions examples/baremetal/cmd/baremetal/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ func (s *server) UpdateJobs(_ context.Context, in *emptypb.Empty) (*emptypb.Empt
return &emptypb.Empty{}, nil
}

// RecoverJob
func (s *server) RecoverJob(_ context.Context, in *pb.Job) (*pb.Job, error) {
slog.Info("RecoverJob")
job, err := s.bm.RecoverJob(baremetal.JobFromPB(in))
errors.Log(err)
return baremetal.JobToPB(job), err
}

func main() {
logx.UserLevel = slog.LevelInfo
opts := cli.DefaultOptions("baremetal", "Bare metal server for job running on bare servers over ssh")
Expand Down
13 changes: 12 additions & 1 deletion examples/baremetal/jobs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading