Skip to content

WebGPU Solver

Fleet optimization is matrix math. Running it on the main thread freezes the UI. CloudSlash offloads it to GPU via WebGPU WGSL compute shaders.


The Compute Bottleneck

Evaluating 50 workloads against 200 compatible instance types generates \(2.4 \times 10^6\) distinct configurations. Running this sequentially in V8 takes over \(9.2\) seconds: way past the interactivity threshold.

We extract the core pricing evaluation loop and write it in the WebGPU Shading Language (WGSL).

WGSL Compute Kernel

Implementation

The WGSL kernel runs in the browser, allocating threads across the GPU's streaming multiprocessors. Invocation indices share no memory arrays; execution is functionally pure.

// cmd/devi-wasm/wgsl/pricing.wgsl

struct Workload {
    cpu_cores    : u32,
    memory_gb    : u32,
    cost_current : f32,
}

struct InstanceType {
    cpu_cores    : u32,
    memory_gb    : u32,
    cost_per_hr  : f32,
    spot_discount: f32,
}

// Memory Bindings mapping external ArrayBuffers
@group(0) @binding(0) var<storage, read>       workloads      : array<Workload>;
@group(0) @binding(1) var<storage, read>       instance_types : array<InstanceType>;
@group(0) @binding(2) var<storage, read_write> results        : array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
    let idx = gid.x;

    // Bounds checking
    if (idx >= arrayLength(&instance_types)) { return; }

    var total_cost : f32 = 0.0;
    let inst = instance_types[idx];

    // Evaluate First-Fit scalar capacities
    for (var w = 0u; w < arrayLength(&workloads); w++) {
        let wl = workloads[w];

        let count = max(
            (wl.cpu_cores + inst.cpu_cores - 1u) / inst.cpu_cores,
            (wl.memory_gb  + inst.memory_gb  - 1u) / inst.memory_gb
        );

        let monthly = inst.cost_per_hr * (1.0 - inst.spot_discount) * 730.0;
        total_cost += f32(count) * monthly;
    }

    results[idx] = total_cost; // Writes result integer to shared memory buffer
}

This kernel runs over 37,500 workgroups (workgroup size of 64), resolving all \(2.4 \times 10^6\) permutations in under \(0.8\) seconds on standard integrated graphics.

Go WASM Interoperability

The Go binary compiled to GOARCH=wasm acts as the execution controller. It uses syscall/js to translate native Go structs into flat Float32Array buffers for WebGPU ingestion:

// cmd/devi-wasm/gpu.go
func ExecuteComputePass(w []Workload, t []InstanceType) []float32 {
    jsWorkloads := marshalWorkloads(w)
    jsInstances := marshalInstances(t)
    resultBuf := make([]float32, len(t))

    js.Global().Get("cloudslash_gpu").Call(
        "runPricingKernel",
        jsWorkloads,
        jsInstances,
        len(t),
        js.FuncOf(func(this js.Value, args []js.Value) interface{} {
            copyFloat32Array(args[0], resultBuf) // ArrayBack resolution
            return nil
        }),
    )

    return resultBuf
}

The returned buffer: the 50 most optimal configurations: feeds into the Go engine's MILP Solver to establish exact provisioning parameters.