音乐
音乐
暂未播放
0:00/0:00
暂无歌词
LeetGPU | 01_Vector_Addition
1178 字
6 分钟
LeetGPU | 01_Vector_Addition
关注 LeetGPU repository,了解更多内容。
Problem Description#
Write a GPU program that performs element-wise addition of two vectors containing 32-bit floating point numbers. The program should take two input vectors of equal length and produce a single output vector containing their sum.
Implementation Requirements#
- External libraries are not permitted.
- The
solvefunction signature must remain unchanged. - The final result must be stored in vector
C.
Example 1#
1Input: A = [1.0, 2.0, 3.0, 4.0]2 B = [5.0, 6.0, 7.0, 8.0]3Output: C = [6.0, 8.0, 10.0, 12.0]Example 2#
1Input: A = [1.5, 1.5, 1.5]2 B = [2.3, 2.3, 2.3]3Output: C = [3.8, 3.8, 3.8]Constraints#
- Input vectors
AandBhave identical lengths. - 1 <=
N<= 100,000,000. - Performance is measured with
N= 25,000,000.
CUDA#
Approach#
CUDA 采用“一元素一线程”的方式,为每个向量元素分配一个 GPU 线程。
- 线程的全局索引由
blockIdx.x、blockDim.x和threadIdx.x共同计算得出。 - 每个索引有效的线程分别从
A和B读取一个元素,完成加法后将结果写入C。 - 每个线程块包含 256 个线程,线程块数量通过向上取整除法确定。
idx < N的边界检查可避免最后一个线程块发生越界访问。- 内核使用 CUDA C++ 编写,并通过
nvcc编译。
Solution#
1#include <cuda_runtime.h>2
3__global__ void vector_add(const float* A, const float* B, float* C, int N) {4 int idx = blockIdx.x * blockDim.x + threadIdx.x;5 if (idx < N) {6 C[idx] = A[idx] + B[idx];7 }8}9
10// A, B, C are device pointers (i.e. pointers to memory on the GPU)11extern "C" void solve(const float* A, const float* B, float* C, int N) {12 int threadsPerBlock = 256;13 int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;14
15 vector_add<<<blocksPerGrid, threadsPerBlock>>>(A, B, C, N);16}Test Code#
1#include <cuda_runtime.h>2
3#include <array>4#include <cmath>5#include <iostream>6
7extern "C" void solve(const float* a, const float* b, float* c, int n);8
9int main() {10 constexpr int n = 4;11 const std::array<float, n> input_a = {1.0f, 2.0f, 3.0f, 4.0f};12 const std::array<float, n> input_b = {5.0f, 6.0f, 7.0f, 8.0f};13 const std::array<float, n> expected = {6.0f, 8.0f, 10.0f, 12.0f};14 std::array<float, n> actual = {};15 constexpr size_t bytes = n * sizeof(float);16
17 float* device_a = nullptr;18 float* device_b = nullptr;19 float* device_c = nullptr;20
21 auto check_cuda = [](cudaError_t status, const char* operation) {22 if (status == cudaSuccess) {23 return true;24 }25 std::cerr << "Test failed. CUDA error in " << operation << ": "26 << cudaGetErrorString(status) << '\n';27 return false;28 };29
30 bool success = check_cuda(cudaMalloc(&device_a, bytes), "cudaMalloc(device_a)") &&31 check_cuda(cudaMalloc(&device_b, bytes), "cudaMalloc(device_b)") &&32 check_cuda(cudaMalloc(&device_c, bytes), "cudaMalloc(device_c)") &&33 check_cuda(cudaMemcpy(device_a, input_a.data(), bytes, cudaMemcpyHostToDevice), "copy input_a") &&34 check_cuda(cudaMemcpy(device_b, input_b.data(), bytes, cudaMemcpyHostToDevice), "copy input_b");35
36 if (success) {37 solve(device_a, device_b, device_c, n);38 success = check_cuda(cudaGetLastError(), "solve") &&39 check_cuda(cudaDeviceSynchronize(), "synchronize") &&40 check_cuda(cudaMemcpy(actual.data(), device_c, bytes, cudaMemcpyDeviceToHost), "copy result");41 }42
43 cudaFree(device_a);44 cudaFree(device_b);45 cudaFree(device_c);46
47 if (!success) {48 return 1;49 }50
51 for (int index = 0; index < n; ++index) {52 if (std::fabs(actual[index] - expected[index]) > 1e-6f) {53 std::cerr << "Test failed at index " << index54 << ". Expected: " << expected[index]55 << ", Actual: " << actual[index] << '\n';56 return 1;57 }58 }59
60 std::cout << "Test passed.\n";61 return 0;62}Test Result#
| Platform | Status | Problem Size | Iterations | Average Time | Minimum Time | Maximum Time | Performance |
|---|---|---|---|---|---|---|---|
| NVIDIA GeForce RTX 5070 Ti Laptop GPU | PASS | N=25000000 | 20 | 0.826 ms | 0.748 ms | 1.325 ms | 363.144 GB/s |
| NVIDIA GeForce RTX 4090 | PASS | N=25000000 | 20 | 0.324 ms | 0.322 ms | 0.327 ms | 926.118 GB/s |
| NVIDIA GeForce RTX 5090 | PASS | N=25000000 | 20 | 0.193 ms | 0.190 ms | 0.195 ms | 1557.852 GB/s |
Triton#
Approach#
Triton 让每个程序实例负责处理一段连续的向量元素。
tl.program_id(0)用于标识当前程序实例。- 每个程序实例最多处理由
tl.arange生成的 1024 个元素。 - 内核分别加载两个数据块,逐元素相加后存储结果。
- 掩码可避免处理最后一个数据块时发生越界加载和存储。
- 内核使用 Python 编写,并由 Triton 即时编译(JIT)为 GPU 代码。
Solution#
1import torch2import triton3import triton.language as tl4
5
6@triton.jit7def vector_add_kernel(a, b, c, n_elements, BLOCK_SIZE: tl.constexpr):8 pid = tl.program_id(0)9
10 block_start = pid * BLOCK_SIZE11 offsets = block_start + tl.arange(0, BLOCK_SIZE)12 mask=offsets<n_elements13
14 a_block = tl.load(a+offsets, mask=mask)15 b_block = tl.load(b+offsets, mask=mask)16
17 c_block = a_block+b_block18
19 tl.store(c+offsets, c_block, mask=mask)20
21
22# a, b, c are tensors on the GPU23def solve(a: torch.Tensor, b: torch.Tensor, c: torch.Tensor, N: int):24 BLOCK_SIZE = 102425 grid = (triton.cdiv(N, BLOCK_SIZE),)26 vector_add_kernel[grid](a, b, c, N, BLOCK_SIZE)Test Code#
1import importlib.util2import sys3from pathlib import Path4
5import torch6
7
8def load_implementation():9 source_path = Path(__file__).resolve().parents[2] / "src" / "triton" / "01_Vector_Addition.py"10 spec = importlib.util.spec_from_file_location("vector_addition_triton_minimal", source_path)11 if spec is None or spec.loader is None:12 raise RuntimeError(f"Unable to load implementation: {source_path}")13 module = importlib.util.module_from_spec(spec)14 spec.loader.exec_module(module)15 return module16
17
18def main():19 input_a = torch.tensor([1.0, 2.0, 3.0, 4.0], device="cuda")20 input_b = torch.tensor([5.0, 6.0, 7.0, 8.0], device="cuda")21 expected = torch.tensor([6.0, 8.0, 10.0, 12.0], device="cuda")22 actual = torch.empty_like(input_a)23
24 load_implementation().solve(input_a, input_b, actual, input_a.numel())25 torch.cuda.synchronize()26 torch.testing.assert_close(actual, expected)27 print("Test passed.")28
29
30if __name__ == "__main__":31 try:32 main()33 except Exception as error:34 print(f"Test failed: {error}", file=sys.stderr)35 raiseTest Result#
| Platform | Status | Problem Size | Iterations | Average Time | Minimum Time | Maximum Time | Performance |
|---|---|---|---|---|---|---|---|
| NVIDIA GeForce RTX 5070 Ti Laptop GPU | PASS | N=25000000 | 20 | 0.809 ms | 0.764 ms | 1.085 ms | 371.021 GB/s |
| NVIDIA GeForce RTX 4090 | PASS | N=25000000 | 20 | 0.341 ms | 0.338 ms | 0.350 ms | 880.608 GB/s |
| NVIDIA GeForce RTX 5090 | PASS | N=25000000 | 20 | 0.223 ms | 0.216 ms | 0.251 ms | 1344.240 GB/s |
PyTorch#
Approach#
PyTorch 通过内置的 torch.add 算子完成向量加法。
torch.add(A, B, out=C)将对应位置的元素相加,并把结果直接写入C。- PyTorch 会自动选择合适的 GPU 内核并发起执行。
- 线程调度、索引计算和边界处理均由 PyTorch 在内部完成。
- 为满足接口要求,函数签名中保留了
N,但该实现不会直接使用它。
Solution#
1import torch2
3
4# A, B, C are tensors on the GPU5def solve(A: torch.Tensor, B: torch.Tensor, C: torch.Tensor, N: int):6 torch.add(A,B,out = C);Test Code#
1import importlib.util2import sys3from pathlib import Path4
5import torch6
7
8def load_implementation():9 source_path = Path(__file__).resolve().parents[2] / "src" / "pytorch" / "01_Vector_Addition.py"10 spec = importlib.util.spec_from_file_location("vector_addition_pytorch_minimal", source_path)11 if spec is None or spec.loader is None:12 raise RuntimeError(f"Unable to load implementation: {source_path}")13 module = importlib.util.module_from_spec(spec)14 spec.loader.exec_module(module)15 return module16
17
18def main():19 input_a = torch.tensor([1.0, 2.0, 3.0, 4.0], device="cuda")20 input_b = torch.tensor([5.0, 6.0, 7.0, 8.0], device="cuda")21 expected = torch.tensor([6.0, 8.0, 10.0, 12.0], device="cuda")22 actual = torch.empty_like(input_a)23
24 load_implementation().solve(input_a, input_b, actual, input_a.numel())25 torch.cuda.synchronize()26 torch.testing.assert_close(actual, expected)27 print("Test passed.")28
29
30if __name__ == "__main__":31 try:32 main()33 except Exception as error:34 print(f"Test failed: {error}", file=sys.stderr)35 raiseTest Result#
| Platform | Status | Problem Size | Iterations | Average Time | Minimum Time | Maximum Time | Performance |
|---|---|---|---|---|---|---|---|
| NVIDIA GeForce RTX 5070 Ti Laptop GPU | PASS | N=25000000 | 20 | 0.817 ms | 0.731 ms | 1.077 ms | 367.031 GB/s |
| NVIDIA GeForce RTX 4090 | PASS | N=25000000 | 20 | 0.330 ms | 0.329 ms | 0.334 ms | 909.717 GB/s |
| NVIDIA GeForce RTX 5090 | PASS | N=25000000 | 20 | 0.207 ms | 0.204 ms | 0.216 ms | 1450.363 GB/s |
References#
关注 LeetGPU repository,了解更多内容。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
LeetGPU | 01_Vector_Addition
https://github.com/HaoyangPing0324/LeetGPU最后更新于 2026-07-20
部分内容可能已过时
相关文章智能推荐
1
LeetGPU | 02_Matrix_Multiplication
LeetGPULeetGPU Matrix Multiplication 题解:CUDA、Triton 与 PyTorch 实现。
2
推理结构地基
llm-algo-leetcode 推理优化Datawhale llm-algo-leetcode 推理优化课程 Task 0(Attention MHA 与 GQA)学习笔记,正在完善中。
3
从 Logits 到 Token:解码采样策略
llm-algo-leetcode 推理优化从 Logits 到 Token 的解码采样策略:Temperature、Top-K、Top-P(Nucleus)原理,以及 Claude Code 文字水印技术。Datawhale llm-algo-leetcode 推理优化课程 Task 3 笔记。
4
Speculative Decoding
llm-algo-leetcode 推理优化投机解码(Speculative Decoding)与多 token 解码技术:基本原理、分类,以及 MTP、DFlash、DSpark 概览。Datawhale llm-algo-leetcode 推理优化课程 Task 3 笔记。
5
KV Cache 与推理服务内存管理
llm-algo-leetcode 推理优化KV Cache 与推理服务内存管理:vLLM PagedAttention、SGLang RadixAttention、Prefix Caching 与 Chunked Prefill。Datawhale llm-algo-leetcode 推理优化课程 Task 4 笔记,正在完善中。
随机文章随机推荐
暂无随机文章
评论区
分享你的想法,与大家交流讨论
站点统计
文章
118
分类
20
标签
164
总字数
1,050,769
运行时长
0 天
最后活动
0 天前
最新动态
2026.09.04
过往皆是序章,前路漫有星光
2026.09.02
九月风至,赴约燕园
2026.07.06
岁次壬寅,序属季夏。负箧吴江,栖迟久泳。时维高考新败,登阊门而北望,临胥江以长嗟。昔者子安命蹇,尚能奋藻于滕阁;今吾才疏,岂可沉沦于吴市?乃焚膏以继晷,立雪而追贤。自暑月即研电学之微,探数理之奥。但求踔厉侪辈,砥砺锋芒。 洎乎素商既至,庠序始开。选修五门皆得满绩,总评冠绝同侪。然尘世难料,人心叵测。交非其人,悔吝丛生。一载相交,竟转瞬成参商。当是时也,恍若屈子见放,贾生受谗。然仲尼厄而作春秋,左丘眇而厥有国语。经此砥砺,竟愈宿疾:昔之曲意逢迎,今则坦荡自持;向之汲汲人言,今则泰然自若。所谓塞翁失马,焉知非福耶? 若夫玄冥司节,青阳启序。既专课业,复骋赛场。数模电赛,殚精竭虑;车赛集创,呕心镂骨。常观吴江夜月,每伴姑苏晨星。悬梁刺股,非为功名之累;凿壁囊萤,实怀鸿鹄之志。终使课业蝉联榜首,竞赛累获殊荣。然形神俱瘁,犹记寒宵病骨,强支案牍;伏暑昏眩,犹自深研不辍。 岁次甲辰,时逢白藏。绩点累年称冠,奖项盈箧成行。遂膺国奖之荣,如登龙门之津。乃遍谒名师,广求良策。拟鹏徙南冥,期凤鸣岐阳。幸得燕园李萌先生青眼,许列门墙。继入艾捷科芯实习,兼修毕业设计。两事交并,心力俱疲。承钟林峰师兄鼎力,终克难关。 今当辞别葑溪,将赴燕台。忆昔韩洪润学长,指迷津于暗夜;念吴圣洁挚友,伴苦读于寒窗。实乃天眷优渥,得遇诸君。昔者范公划粥,终成社稷之臣;欧母画荻,乃育文章之伯。予虽驽钝,敢不踵武前修?悟已往之不谏,知来者之可追。陶元亮归去来辞,实获我心;王子安穷且益坚,宁移素志?今将整装而北发,岂效楚囚之泣?当乘长风,破巨浪,展鸿图于未央!
日
一
二
三
四
五
六
文章目录
--
总访问量
--
访客数
公告
音乐
音乐
暂未播放
0:00/0:00
暂无歌词
站点统计
文章
118
分类
20
标签
164
总字数
1,050,769
运行时长
0 天
最后活动
0 天前
最新动态
2026.09.04
过往皆是序章,前路漫有星光
2026.09.02
九月风至,赴约燕园
2026.07.06
岁次壬寅,序属季夏。负箧吴江,栖迟久泳。时维高考新败,登阊门而北望,临胥江以长嗟。昔者子安命蹇,尚能奋藻于滕阁;今吾才疏,岂可沉沦于吴市?乃焚膏以继晷,立雪而追贤。自暑月即研电学之微,探数理之奥。但求踔厉侪辈,砥砺锋芒。 洎乎素商既至,庠序始开。选修五门皆得满绩,总评冠绝同侪。然尘世难料,人心叵测。交非其人,悔吝丛生。一载相交,竟转瞬成参商。当是时也,恍若屈子见放,贾生受谗。然仲尼厄而作春秋,左丘眇而厥有国语。经此砥砺,竟愈宿疾:昔之曲意逢迎,今则坦荡自持;向之汲汲人言,今则泰然自若。所谓塞翁失马,焉知非福耶? 若夫玄冥司节,青阳启序。既专课业,复骋赛场。数模电赛,殚精竭虑;车赛集创,呕心镂骨。常观吴江夜月,每伴姑苏晨星。悬梁刺股,非为功名之累;凿壁囊萤,实怀鸿鹄之志。终使课业蝉联榜首,竞赛累获殊荣。然形神俱瘁,犹记寒宵病骨,强支案牍;伏暑昏眩,犹自深研不辍。 岁次甲辰,时逢白藏。绩点累年称冠,奖项盈箧成行。遂膺国奖之荣,如登龙门之津。乃遍谒名师,广求良策。拟鹏徙南冥,期凤鸣岐阳。幸得燕园李萌先生青眼,许列门墙。继入艾捷科芯实习,兼修毕业设计。两事交并,心力俱疲。承钟林峰师兄鼎力,终克难关。 今当辞别葑溪,将赴燕台。忆昔韩洪润学长,指迷津于暗夜;念吴圣洁挚友,伴苦读于寒窗。实乃天眷优渥,得遇诸君。昔者范公划粥,终成社稷之臣;欧母画荻,乃育文章之伯。予虽驽钝,敢不踵武前修?悟已往之不谏,知来者之可追。陶元亮归去来辞,实获我心;王子安穷且益坚,宁移素志?今将整装而北发,岂效楚囚之泣?当乘长风,破巨浪,展鸿图于未央!



