Install any skill in seconds. Free to start, no credit card required.
Get Started Free →GPU parallel algorithm design patterns and implementations. Implement parallel reduction, scan/prefix sum, histogram, parallel sort algorithms, stream compaction, and work-efficient patterns optimized for specific GPU architectures.
.claude/skills/a5c-ai-parallel-patterns/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 97% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 61% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 257% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 78% | 0% |
You are parallel-patterns - a specialized skill for GPU parallel algorithm design patterns and implementations. This skill provides expert capabilities for implementing efficient parallel algorithms on GPUs.
This skill enables AI-powered parallel algorithm development including:
Implement efficient reductions:
cuda// Warp-level reduction (no shared memory needed for single warp) __device__ float warpReduce(float val) { for (int offset = warpSize / 2; offset > 0; offset >>= 1) { val += __shfl_down_sync(0xffffffff, val, offset); } return val; } // Block-level reduction with shared memory template<int BLOCK_SIZE> __device__ float blockReduce(float val) { __shared__ float shared[32]; // One slot per warp int lane = threadIdx.x % warpSize; int wid = threadIdx.x / warpSize; // Warp-level reduction val = warpReduce(val); // Write warp results to shared memory if (lane == 0) shared[wid] = val; __syncthreads(); // First warp reduces warp results val = (threadIdx.x < BLOCK_SIZE / warpSize) ? shared[lane] : 0.0f; if (wid == 0) val = warpReduce(val); return val; } // Full parallel reduction kernel template<int BLOCK_SIZE> __global__ void reduceKernel(const float* input, float* output, int n) { float sum = 0.0f; // Grid-stride loop for large arrays for (int i = blockIdx.x * BLOCK_SIZE + threadIdx.x; i < n; i += gridDim.x * BLOCK_SIZE) { sum += input[i]; } // Block reduction sum = blockReduce<BLOCK_SIZE>(sum); // Write block result if (threadIdx.x == 0) { atomicAdd(output, sum); } }
Work-efficient scan implementations:
cuda// Inclusive scan within a warp __device__ float warpInclusiveScan(float val) { for (int offset = 1; offset < warpSize; offset <<= 1) { float n = __shfl_up_sync(0xffffffff, val, offset); if (threadIdx.x % warpSize >= offset) val += n; } return val; } // Block-level inclusive scan (Blelloch algorithm) template<int BLOCK_SIZE> __device__ void blockInclusiveScan(float* data) { int tid = threadIdx.x; // Up-sweep (reduce) phase for (int stride = 1; stride < BLOCK_SIZE; stride <<= 1) { int index = (tid + 1) * stride * 2 - 1; if (index < BLOCK_SIZE) { data[index] += data[index - stride]; } __syncthreads(); } // Clear last element for exclusive scan // if (tid == 0) data[BLOCK_SIZE - 1] = 0; // __syncthreads(); // Down-sweep phase for (int stride = BLOCK_SIZE / 2; stride > 0; stride >>= 1) { int index = (tid + 1) * stride * 2 - 1; if (index + stride < BLOCK_SIZE) { data[index + stride] += data[index]; } __syncthreads(); } } // Using CUB for production code #include <cub/cub.cuh> void inclusiveScan(float* d_in, float* d_out, int n) { void* d_temp_storage = nullptr; size_t temp_storage_bytes = 0; // Get required storage cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, d_in, d_out, n); // Allocate temporary storage cudaMalloc(&d_temp_storage, temp_storage_bytes); // Run scan cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, d_in, d_out, n); cudaFree(d_temp_storage); }
Parallel histogram computation:
cuda// Shared memory histogram (small number of bins) __global__ void histogramSmall(const int* input, int* histogram, int n, int numBins) { __shared__ int localHist[256]; // Initialize local histogram for (int i = threadIdx.x; i < numBins; i += blockDim.x) { localHist[i] = 0; } __syncthreads(); // Accumulate into local histogram int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n) { int bin = input[idx]; atomicAdd(&localHist[bin], 1); } __syncthreads(); // Merge to global histogram for (int i = threadIdx.x; i < numBins; i += blockDim.x) { atomicAdd(&histogram[i], localHist[i]); } } // Per-thread private histograms for large bin counts __global__ void histogramPrivate(const int* input, int* histogram, int n, int numBins) { extern __shared__ int sharedHist[]; int tid = threadIdx.x; int* myHist = &sharedHist[tid * numBins]; // Initialize private histogram for (int i = 0; i < numBins; i++) { myHist[i] = 0; } // Accumulate for (int i = blockIdx.x * blockDim.x + tid; i < n; i += gridDim.x * blockDim.x) { myHist[input[i]]++; } __syncthreads(); // Reduce private histograms for (int bin = tid; bin < numBins; bin += blockDim.x) { int sum = 0; for (int t = 0; t < blockDim.x; t++) { sum += sharedHist[t * numBins + bin]; } atomicAdd(&histogram[bin], sum); } }
Parallel radix sort:
cuda// Using CUB/Thrust for production #include <cub/cub.cuh> void radixSort(unsigned int* d_keys, unsigned int* d_values, int n) { void* d_temp_storage = nullptr; size_t temp_storage_bytes = 0; // Double buffer for efficient sorting cub::DoubleBuffer<unsigned int> d_keys_db(d_keys, d_keys_alt); cub::DoubleBuffer<unsigned int> d_values_db(d_values, d_values_alt); // Get storage requirements cub::DeviceRadixSort::SortPairs(d_temp_storage, temp_storage_bytes, d_keys_db, d_values_db, n); cudaMalloc(&d_temp_storage, temp_storage_bytes); // Sort cub::DeviceRadixSort::SortPairs(d_temp_storage, temp_storage_bytes, d_keys_db, d_values_db, n); cudaFree(d_temp_storage); } // Basic radix sort building block __global__ void countRadixDigits(const unsigned int* keys, int* counts, int n, int shift) { __shared__ int localCounts[16]; // 4-bit radix if (threadIdx.x < 16) localCounts[threadIdx.x] = 0; __syncthreads(); int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n) { int digit = (keys[idx] >> shift) & 0xF; atomicAdd(&localCounts[digit], 1); } __syncthreads(); if (threadIdx.x < 16) { atomicAdd(&counts[blockIdx.x * 16 + threadIdx.x], localCounts[threadIdx.x]); } }
Filter and compact arrays:
cuda// Simple compaction with atomic counter __global__ void compactAtomic(const int* input, const int* flags, int* output, int* counter, int n) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n && flags[idx]) { int pos = atomicAdd(counter, 1); output[pos] = input[idx]; } } // Efficient compaction with scan // Step 1: Generate flags __global__ void generateFlags(const float* input, int* flags, int n, float threshold) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n) { flags[idx] = (input[idx] > threshold) ? 1 : 0; } } // Step 2: Exclusive scan on flags (gives output positions) // Step 3: Scatter to output positions __global__ void scatter(const float* input, const int* flags, const int* positions, float* output, int n) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n && flags[idx]) { output[positions[idx]] = input[idx]; } } // Using CUB select #include <cub/cub.cuh> void compactWithCUB(float* d_in, float* d_out, int* d_num_selected, int n) { void* d_temp_storage = nullptr; size_t temp_storage_bytes = 0; auto select_op = [] __device__ (float val) { return val > 0.0f; }; cub::DeviceSelect::If(d_temp_storage, temp_storage_bytes, d_in, d_out, d_num_selected, n, select_op); cudaMalloc(&d_temp_storage, temp_storage_bytes); cub::DeviceSelect::If(d_temp_storage, temp_storage_bytes, d_in, d_out, d_num_selected, n, select_op); cudaFree(d_temp_storage); }
Merge sorted sequences:
cuda// Binary search for merge path __device__ int binarySearch(const int* data, int target, int left, int right) { while (left < right) { int mid = (left + right) / 2; if (data[mid] < target) { left = mid + 1; } else { right = mid; } } return left; } // Merge path parallel merge __global__ void parallelMerge(const int* A, int sizeA, const int* B, int sizeB, int* output) { int tid = blockIdx.x * blockDim.x + threadIdx.x; int totalSize = sizeA + sizeB; if (tid < totalSize) { // Find merge path coordinates int diagonal = tid; int aStart = max(0, diagonal - sizeB); int aEnd = min(diagonal, sizeA); // Binary search on merge path while (aStart < aEnd) { int aMid = (aStart + aEnd) / 2; int bMid = diagonal - aMid - 1; if (bMid >= 0 && bMid < sizeB && A[aMid] > B[bMid]) { aEnd = aMid; } else { aStart = aMid + 1; } } int aIdx = aStart; int bIdx = diagonal - aStart; // Determine which element goes to this position if (aIdx < sizeA && (bIdx >= sizeB || A[aIdx] <= B[bIdx])) { output[tid] = A[aIdx]; } else { output[tid] = B[bIdx]; } } }
Load-balanced work distribution:
cuda// Persistent threads pattern __global__ void persistentKernel(int* workQueue, int* queueSize, int* results) { __shared__ int nextItem; while (true) { // Get next work item if (threadIdx.x == 0) { nextItem = atomicAdd(queueSize, -1) - 1; } __syncthreads(); if (nextItem < 0) break; // Process work item int workItem = workQueue[nextItem]; // ... do work ... } } // Dynamic parallelism for irregular workloads __global__ void adaptiveKernel(int* data, int n, int threshold) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx >= n) return; int workload = computeWorkload(data[idx]); if (workload > threshold) { // Launch child kernel for heavy work processHeavy<<<1, 128>>>(data, idx); } else { // Process light work inline processLight(data, idx); } }
This skill integrates with the following processes:
parallel-algorithm-design.js - Algorithm design workflowreduction-scan-implementation.js - Reduction/scan implementationsatomic-operations-synchronization.js - Atomic patternsjson{ "operation": "generate-pattern", "pattern": "parallel-reduction", "configuration": { "data_type": "float", "reduction_op": "sum", "block_size": 256, "use_warp_shuffle": true }, "generated_code": { "kernel_file": "reduction.cu", "lines": 85 }, "performance_estimate": { "memory_bound": true, "bandwidth_utilization": 0.85, "operations_per_element": 1 } }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 23,361 | 21,547 | -8% | 1 | 1 | 0% | 3,632 | 6,111 | +68% | 0 | 0 | — |
case-02 | fail→pass | 20,203 | 18,810 | -7% | 1 | 1 | 0% | 3,710 | 7,298 | +97% | 0 | 0 | — |
case-03 | fail→pass | 20,967 | 13,248 | -37% | 1 | 1 | 0% | 3,966 | 6,394 | +61% | 0 | 0 | — |
case-04 | pass→pass | 19,319 | 13,830 | -28% | 1 | 1 | 0% | 2,800 | 5,741 | +105% | 0 | 0 | — |
case-05 | pass→pass | 17,913 | 20,948 | +17% | 1 | 1 | 0% | 3,408 | 6,767 | +99% | 0 | 0 | — |
case-06 | pass→pass | 6,398 | 6,622 | +4% | 1 | 1 | 0% | 1,118 | 4,666 | +317% | 0 | 0 | — |
case-07 | fail→fail | 11,934 | 20,457 | +71% | 1 | 1 | 0% | 1,990 | 5,483 | +176% | 0 | 0 | — |
case-08 | fail→pass | 12,065 | 14,062 | +17% | 1 | 1 | 0% | 1,756 | 6,261 | +257% | 0 | 0 | — |
case-09 | pass→pass | 12,438 | 8,701 | -30% | 1 | 1 | 0% | 2,283 | 5,404 | +137% | 0 | 0 | — |
case-10 | fail→pass | 20,713 | 9,933 | -52% | 1 | 1 | 0% | 3,152 | 5,623 | +78% | 0 | 0 | — |
case-11 | fail→fail | 16,009 | 12,435 | -22% | 1 | 1 | 0% | 2,746 | 5,806 | +111% | 0 | 0 | — |
case-12 | fail→fail | 25,315 | 13,034 | -49% | 1 | 1 | 0% | 4,922 | 6,123 | +24% | 0 | 0 | — |
case-13 | fail→fail | 14,938 | 8,737 | -42% | 1 | 1 | 0% | 2,445 | 5,272 | +116% | 0 | 0 | — |
case-14 | fail→pass | 18,046 | 8,115 | -55% | 1 | 1 | 0% | 2,815 | 5,296 | +88% | 0 | 0 | — |
case-15 | fail→fail | 10,646 | 13,507 | +27% | 1 | 1 | 0% | 1,546 | 5,726 | +270% | 0 | 0 | — |
case-16 | pass→pass | 10,432 | 6,184 | -41% | 1 | 1 | 0% | 1,412 | 4,816 | +241% | 0 | 0 | — |
case-17 | fail→fail | 14,174 | 18,266 | +29% | 1 | 1 | 0% | 2,829 | 7,214 | +155% | 0 | 0 | — |
case-18 | pass→pass | 7,458 | 17,258 | +131% | 1 | 1 | 0% | 1,250 | 6,053 | +384% | 0 | 0 | — |
case-19 | fail→fail | 11,834 | 16,466 | +39% | 1 | 1 | 0% | 2,179 | 6,687 | +207% | 0 | 0 | — |
case-20 | fail→fail | 13,461 | 14,061 | +4% | 1 | 1 | 0% | 3,082 | 5,921 | +92% | 0 | 0 | — |
case-21 | fail→fail | 21,822 | 23,896 | +10% | 1 | 1 | 0% | 3,064 | 7,212 | +135% | 0 | 0 | — |
case-22 | pass→pass | 12,722 | 7,803 | -39% | 1 | 1 | 0% | 2,107 | 4,969 | +136% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.