Files
rustytorch/crates/specialized/rtx-cfd/src/kernels/cuda/e3_cg.cu
T
Omar SobhandClaude Fable 5.1 77fda442c6
CI / Build CPU-Only (Explicit) (push) Failing after 4s
CI / Format Check (push) Failing after 4s
Documentation / Build User Guide (push) Successful in 4s
Documentation / Build API Documentation (push) Failing after 30s
CI / Clippy Check (push) Failing after 1m0s
CI / Build (ubuntu-latest) (push) Failing after 2m53s
Performance Benchmarks / Run Benchmarks (push) Successful in 3m27s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (ubuntu-latest) (push) Canceled after 0s
CI / WASM Build + Size Check (push) Canceled after 0s
CI / Distributed Training Tests (push) Canceled after 0s
CI / CI Success (push) Canceled after 0s
embedded3 PERF-3 P1-5 (c) part 1: scatter kernels (e3_scat_{f64,f32,u32,i32}) in the CG module; the refresh's seven f64 coefficient arrays and z links, and the V-cycle fine level's f32 arrays and maps, scattered on the changed rows into persistent buffers (DeviceVcycle::refresh_fine_rows) — slab CSV byte-identical, band check passed, device moving/cg green; ny 124 rebuild block 1,895 → 1,748 ms per step. The first form redirected the V-cycle's own e3_cg_scatter_f64 launch (a replace-all on the launch name) and failed every gate — the symbol table is the first thing to read when adding to a module
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-20 18:09:02 -05:00

225 lines
8.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* embedded3 item 3: the f64 conjugate gradient's maps on the device over
* the active cells (index list), with FIXED-ORDER reductions: every block
* reduces its 256 lanes by the same shared-memory tree and writes one
* partial; `e3_cg_reduce` sums the partials in index order on one thread.
* Run-to-run bit-identical by construction (no atomics).
*/
#define NONE 0xFFFFFFFFu
/* The seven-point neighbour sum plus the cell's off-stencil links (CSR:
* link_ptr[g] .. link_ptr[g + 1]; the virtually merged small cells). */
__device__ __forceinline__ double nb_sum3d(
int g, int nx, const double* ae, const double* aw, const double* an, const double* as_,
const double* at, const double* ab, const unsigned int* top, const unsigned int* bot,
const unsigned int* link_ptr, const unsigned int* link_idx, const double* link_coef,
const double* x)
{
double s = 0.0;
double e = ae[g]; if (e != 0.0) s += e * x[g + 1];
double w = aw[g]; if (w != 0.0) s += w * x[g - 1];
double nn = an[g]; if (nn != 0.0) s += nn * x[g + nx];
double ss = as_[g]; if (ss != 0.0) s += ss * x[g - nx];
double t = at[g]; if (t != 0.0) s += t * x[top[g]];
double b = ab[g]; if (b != 0.0) s += b * x[bot[g]];
for (unsigned int l = link_ptr[g]; l < link_ptr[g + 1]; ++l) s += link_coef[l] * x[link_idx[l]];
return s;
}
__device__ __forceinline__ double block_reduce(double v)
{
__shared__ double sh[256];
int t = threadIdx.x;
sh[t] = v;
__syncthreads();
for (int s = 128; s > 0; s >>= 1) {
if (t < s) sh[t] += sh[t + s];
__syncthreads();
}
return sh[0];
}
/* q = A d on the cells. */
extern "C" __global__ void e3_cg_spmv(
int n_cells, const unsigned int* __restrict__ cells,
const double* __restrict__ ae, const double* __restrict__ aw,
const double* __restrict__ an, const double* __restrict__ as_,
const double* __restrict__ at, const double* __restrict__ ab,
const unsigned int* __restrict__ top, const unsigned int* __restrict__ bot,
const unsigned int* __restrict__ link_ptr, const unsigned int* __restrict__ link_idx,
const double* __restrict__ link_coef,
const double* __restrict__ ap, const double* __restrict__ d, double* __restrict__ q, int nx)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
q[g] = ap[g] * d[g] - nb_sum3d(g, nx, ae, aw, an, as_, at, ab, top, bot, link_ptr, link_idx, link_coef, d);
}
/* r = b A p on the cells; partial[block] = Σ |r| over the block's cells. */
extern "C" __global__ void e3_cg_residual(
int n_cells, const unsigned int* __restrict__ cells,
const double* __restrict__ ae, const double* __restrict__ aw,
const double* __restrict__ an, const double* __restrict__ as_,
const double* __restrict__ at, const double* __restrict__ ab,
const unsigned int* __restrict__ top, const unsigned int* __restrict__ bot,
const unsigned int* __restrict__ link_ptr, const unsigned int* __restrict__ link_idx,
const double* __restrict__ link_coef,
const double* __restrict__ ap, const double* __restrict__ b,
const double* __restrict__ p, double* __restrict__ r, double* __restrict__ partial, int nx)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
double v = 0.0;
if (t < n_cells) {
int g = cells[t];
v = b[g] - (ap[g] * p[g] - nb_sum3d(g, nx, ae, aw, an, as_, at, ab, top, bot, link_ptr, link_idx, link_coef, p));
r[g] = v;
v = fabs(v);
}
double s = block_reduce(v);
if (threadIdx.x == 0) partial[blockIdx.x] = s;
}
/* partial[block] = Σ a·b over the block's cells (b = a for a norm). */
extern "C" __global__ void e3_cg_dot_partial(
int n_cells, const unsigned int* __restrict__ cells,
const double* __restrict__ a, const double* __restrict__ b, double* __restrict__ partial)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
double v = 0.0;
if (t < n_cells) { int g = cells[t]; v = a[g] * b[g]; }
double s = block_reduce(v);
if (threadIdx.x == 0) partial[blockIdx.x] = s;
}
/* partial[block] = Σ |a| over the block's cells. */
extern "C" __global__ void e3_cg_l1_partial(
int n_cells, const unsigned int* __restrict__ cells,
const double* __restrict__ a, double* __restrict__ partial)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
double v = 0.0;
if (t < n_cells) v = fabs(a[cells[t]]);
double s = block_reduce(v);
if (threadIdx.x == 0) partial[blockIdx.x] = s;
}
/* partial[block] = Σ a over the block's cells. */
extern "C" __global__ void e3_cg_sum_partial(
int n_cells, const unsigned int* __restrict__ cells,
const double* __restrict__ a, double* __restrict__ partial)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
double v = 0.0;
if (t < n_cells) v = a[cells[t]];
double s = block_reduce(v);
if (threadIdx.x == 0) partial[blockIdx.x] = s;
}
/* out[0] = Σ partial[0..n) in index order, one thread. */
extern "C" __global__ void e3_cg_reduce(int n, const double* __restrict__ partial, double* __restrict__ out)
{
if (blockIdx.x * blockDim.x + threadIdx.x != 0) return;
double s = 0.0;
for (int i = 0; i < n; ++i) s += partial[i];
out[0] = s;
}
/* p += alpha d; r -= alpha q. */
extern "C" __global__ void e3_cg_axpy2(
int n_cells, const unsigned int* __restrict__ cells, double alpha,
const double* __restrict__ d, const double* __restrict__ q,
double* __restrict__ p, double* __restrict__ r)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
p[g] += alpha * d[g];
r[g] -= alpha * q[g];
}
/* y += alpha x over the cells (PERF-3 P2: the projected initial guess). */
extern "C" __global__ void e3_cg_axpy(
int n_cells, const unsigned int* __restrict__ cells, double alpha,
const double* __restrict__ x, double* __restrict__ y)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
y[g] += alpha * x[g];
}
/* d = z + beta d. */
extern "C" __global__ void e3_cg_xpay(
int n_cells, const unsigned int* __restrict__ cells, double beta,
const double* __restrict__ z, double* __restrict__ d)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
d[g] = z[g] + beta * d[g];
}
/* dst = src (copy over the cells). */
extern "C" __global__ void e3_cg_copy(
int n_cells, const unsigned int* __restrict__ cells,
const double* __restrict__ src, double* __restrict__ dst)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
dst[g] = src[g];
}
/* v -= s over the cells. */
extern "C" __global__ void e3_cg_shift(
int n_cells, const unsigned int* __restrict__ cells, double s, double* __restrict__ v)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
v[cells[t]] -= s;
}
/* f32 b0 = (float) r over the cells; f64 z = (double) x0 over the cells. */
extern "C" __global__ void e3_cg_gather_f32(
int n_cells, const unsigned int* __restrict__ cells, const double* __restrict__ r, float* __restrict__ b0)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
b0[g] = (float) r[g];
}
extern "C" __global__ void e3_cg_scatter_f64(
int n_cells, const unsigned int* __restrict__ cells, const float* __restrict__ x0, double* __restrict__ z)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t >= n_cells) return;
int g = cells[t];
z[g] = (double) x0[g];
}
/* P1-5 (c): scatter compact (index, value) lists into persistent buffers. */
extern "C" __global__ void e3_scat_f64(int n, const unsigned int* __restrict__ idx, const double* __restrict__ val, double* __restrict__ dst)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t < n) dst[idx[t]] = val[t];
}
extern "C" __global__ void e3_scat_f32(int n, const unsigned int* __restrict__ idx, const float* __restrict__ val, float* __restrict__ dst)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t < n) dst[idx[t]] = val[t];
}
extern "C" __global__ void e3_scat_u32(int n, const unsigned int* __restrict__ idx, const unsigned int* __restrict__ val, unsigned int* __restrict__ dst)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t < n) dst[idx[t]] = val[t];
}
extern "C" __global__ void e3_scat_i32(int n, const unsigned int* __restrict__ idx, const int* __restrict__ val, int* __restrict__ dst)
{
int t = blockIdx.x * blockDim.x + threadIdx.x;
if (t < n) dst[idx[t]] = val[t];
}