摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/12/03

news2025/1/16 18:49:30

 Learning Roadmap:

Section 1: Intro to Parallel Programming & MUSA

  1. Deep Learning Ecosystem(摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/11/30-CSDN博客)
  2. Ubuntu+Driver+Toolkit+conda+pytorch+torch_musa环境安装(2024/11/24-Ubuntu Windows双系统安装 | 2024/11/30-GPU驱动&MUSA Toolkit安装)
  3. C/C++ Review(摩尔线程国产显卡 MUSA 并行编程学习笔记-2024/11/22-CSDN博客)
  4. GPU intros(摩尔线程国产显卡 MUSA 并行编程学习笔记-2024/11/25-CSDN博客)
  5. GPU硬件架构 (摩尔线程国产显卡 MUSA 并行编程学习笔记-2024/11/26-CSDN博客)
  6. Write First Kernels (Here) (2024/11/27-线程层级 | 2024/11/28-First MUSA Kernel to Count Thread | 2024/12/02-向量相加)
  7. MUSA API
  8. Faster Matrix Multiplication
  9. Triton
  10. Pytorch Extensions(摩尔线程国产显卡 MUSA 并行编程学习笔记-2024/11/21-CSDN博客)
  11. MNIST Multilayer Perceptron

Section 2: Parallel Programming & MUSA in Depth

  1. Analyzing Parallel Program Performance on a Quad-Core CPU
  2. Scheduling Task Graphs on a Multi-Core CPU
  3. A Simple Renderer in MUSA
  4. Optimizing DNN Performance on DNN Accelerator Hardware
  5. llm.c

Ref:摩尔学院 High-Performance Computing with GPUs | Stanford CS149 - Video | Stanford CS149 - Syllabus

Kernel to Add Vector (3D)

Ref:  High-Performance Computing with GPUs Chapter 5

下面的代码将用CPU与GPU分别对两个长度为1000万的向量进行相加,并计算对应的平均耗时,其中GPU相加分别采用了两种Kernel,其中一个Kernel定义了三维的Block和Grid,另一个Kernel则使用了一维的Block和Grid

代码地址

MUSA PLAY GROUND - Github

代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <musa_runtime.h>
#include <math.h>
#include <iostream>

#define N 10000000  // Vector size = 10 million
#define BLOCK_SIZE_1D 1024
#define BLOCK_SIZE_3D_X 16
#define BLOCK_SIZE_3D_Y 8
#define BLOCK_SIZE_3D_Z 8
// 16 * 16 * 8 = 2048

// CPU vector addition
void vector_add_cpu(float *a, float *b, float *c, int n) {
    for (int i = 0; i < n; i++) {
        c[i] = a[i] + b[i];
    }
}

// MUSA kernel for 1D vector addition
__global__ void vector_add_gpu_1d(float *a, float *b, float *c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    // one add, one multiply, one store
    if (i < n) {
        c[i] = a[i] + b[i];
        // one add, one store
    }
}

// MUSA kernel for 3D vector addition
__global__ void vector_add_gpu_3d(float *a, float *b, float *c, int nx, int ny, int nz) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    int j = blockIdx.y * blockDim.y + threadIdx.y;
    int k = blockIdx.z * blockDim.z + threadIdx.z;
    // 3 adds, 3 multiplies, 3 stores
    
    if (i < nx && j < ny && k < nz) {
        int idx = i + j * nx + k * nx * ny;
        if (idx < nx * ny * nz) {
            c[idx] = a[idx] + b[idx];
        }
    }
    // you get the point...
}

// Initialize vector with random values
void init_vector(float *vec, int n) {
    for (int i = 0; i < n; i++) {
        vec[i] = (float)rand() / RAND_MAX;
    }
}

// Function to measure execution time
double get_time() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec + ts.tv_nsec * 1e-9;
}
int main() {
    float *h_a, *h_b, *h_c_cpu, *h_c_gpu_1d, *h_c_gpu_3d;
    float *d_a, *d_b, *d_c_1d, *d_c_3d;
    size_t size = N * sizeof(float);

    // Allocate host memory
    h_a = (float*)malloc(size);
    h_b = (float*)malloc(size);
    h_c_cpu = (float*)malloc(size);
    h_c_gpu_1d = (float*)malloc(size);
    h_c_gpu_3d = (float*)malloc(size);

    // Initialize vectors
    srand(time(NULL));
    init_vector(h_a, N);
    init_vector(h_b, N);

    // Allocate device memory
    musaMalloc(&d_a, size);
    musaMalloc(&d_b, size);
    musaMalloc(&d_c_1d, size);
    musaMalloc(&d_c_3d, size);

    // Copy data to device
    musaMemcpy(d_a, h_a, size, musaMemcpyHostToDevice);
    musaMemcpy(d_b, h_b, size, musaMemcpyHostToDevice);

    // Define grid and block dimensions for 1D
    int num_blocks_1d = (N + BLOCK_SIZE_1D - 1) / BLOCK_SIZE_1D;

    // Define grid and block dimensions for 3D
    int nx = 100, ny = 100, nz = 1000; // N = 10000000 = 100 * 100 * 1000
    dim3 block_size_3d(BLOCK_SIZE_3D_X, BLOCK_SIZE_3D_Y, BLOCK_SIZE_3D_Z);
    dim3 num_blocks_3d(
        (nx + block_size_3d.x - 1) / block_size_3d.x,
        (ny + block_size_3d.y - 1) / block_size_3d.y,
        (nz + block_size_3d.z - 1) / block_size_3d.z
    );

    // Warm-up runs
    printf("Performing warm-up runs...\n");
    for (int i = 0; i < 3; i++) {
        vector_add_cpu(h_a, h_b, h_c_cpu, N);
        vector_add_gpu_1d<<<num_blocks_1d, BLOCK_SIZE_1D>>>(d_a, d_b, d_c_1d, N);
        vector_add_gpu_3d<<<num_blocks_3d, block_size_3d>>>(d_a, d_b, d_c_3d, nx, ny, nz);
        musaDeviceSynchronize();
    }

    // Benchmark CPU implementation
    printf("Benchmarking CPU implementation...\n");
    double cpu_total_time = 0.0;
    for (int i = 0; i < 5; i++) {
        double start_time = get_time();
        vector_add_cpu(h_a, h_b, h_c_cpu, N);
        double end_time = get_time();
        cpu_total_time += end_time - start_time;
    }
    double cpu_avg_time = cpu_total_time / 5.0;

    // Benchmark GPU 1D implementation
    printf("Benchmarking GPU 1D implementation...\n");
    double gpu_1d_total_time = 0.0;
    for (int i = 0; i < 100; i++) {
        musaMemset(d_c_1d, 0, size);  // Clear previous results
        double start_time = get_time();
        vector_add_gpu_1d<<<num_blocks_1d, BLOCK_SIZE_1D>>>(d_a, d_b, d_c_1d, N);
        musaDeviceSynchronize();
        double end_time = get_time();
        gpu_1d_total_time += end_time - start_time;
    }
    double gpu_1d_avg_time = gpu_1d_total_time / 100.0;

    // Verify 1D results immediately
    musaMemcpy(h_c_gpu_1d, d_c_1d, size, musaMemcpyDeviceToHost);
    bool correct_1d = true;
    for (int i = 0; i < N; i++) {
        if (fabs(h_c_cpu[i] - h_c_gpu_1d[i]) > 1e-4) {
            correct_1d = false;
            std::cout << i << " cpu: " << h_c_cpu[i] << " != " << h_c_gpu_1d[i] << std::endl;
            break;
        }
    }
    printf("1D Results are %s\n", correct_1d ? "correct" : "incorrect");

    // Benchmark GPU 3D implementation
    printf("Benchmarking GPU 3D implementation...\n");
    double gpu_3d_total_time = 0.0;
    for (int i = 0; i < 100; i++) {
        musaMemset(d_c_3d, 0, size);  // Clear previous results
        double start_time = get_time();
        vector_add_gpu_3d<<<num_blocks_3d, block_size_3d>>>(d_a, d_b, d_c_3d, nx, ny, nz);
        musaDeviceSynchronize();
        double end_time = get_time();
        gpu_3d_total_time += end_time - start_time;
    }
    double gpu_3d_avg_time = gpu_3d_total_time / 100.0;

    // Verify 3D results immediately
    musaMemcpy(h_c_gpu_3d, d_c_3d, size, musaMemcpyDeviceToHost);
    bool correct_3d = true;
    for (int i = 0; i < N; i++) {
        if (fabs(h_c_cpu[i] - h_c_gpu_3d[i]) > 1e-4) {
            correct_3d = false;
            std::cout << i << " cpu: " << h_c_cpu[i] << " != " << h_c_gpu_3d[i] << std::endl;
            break;
        }
    }
    printf("3D Results are %s\n", correct_3d ? "correct" : "incorrect");

    // Print results
    printf("CPU average time: %f milliseconds\n", cpu_avg_time * 1000);
    printf("GPU 1D average time: %f milliseconds\n", gpu_1d_avg_time * 1000);
    printf("GPU 3D average time: %f milliseconds\n", gpu_3d_avg_time * 1000);
    printf("Speedup (CPU vs GPU 1D): %fx\n", cpu_avg_time / gpu_1d_avg_time);
    printf("Speedup (CPU vs GPU 3D): %fx\n", cpu_avg_time / gpu_3d_avg_time);
    printf("Speedup (GPU 1D vs GPU 3D): %fx\n", gpu_1d_avg_time / gpu_3d_avg_time);

    // Free memory
    free(h_a);
    free(h_b);
    free(h_c_cpu);
    free(h_c_gpu_1d);
    free(h_c_gpu_3d);
    musaFree(d_a);
    musaFree(d_b);
    musaFree(d_c_1d);
    musaFree(d_c_3d);

    return 0;
}

编译

    mcc 01_vector_add_v2.mu -o vector_add_v2 -mtgpu -O2 -lmusart

   ./vector_add_v2

输出结果

如图所示,结果输出了CPU与GPU 对于长度为1000万的两个向量的相加,20次的平均速度,并验证了结果的准确性,可以看到通过定义3D block & grid的GPU Kernel不如定义了1D block & grid的 GPU Kernel的速度

Notes

如无必要,定义1D Block就可以

  1. 这里可以看到相比定义三维Grid & Block Kernel所需要的3次add, 3次multiplies,3次stores,通过1D Gird & Block 的Kernel只需要1次Add, mutiply 和Store,并且整个代码逻辑上要清晰很多,如果Kernel不是一定要计算三维强相关的任务时,定义1D block & grid在计算与简洁性上均有优势
// MUSA kernel for 1D vector addition
__global__ void vector_add_gpu_1d(float *a, float *b, float *c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    // one add, one multiply, one store
    if (i < n) {
        c[i] = a[i] + b[i];
        // one add, one store
    }
}

// MUSA kernel for 3D vector addition
__global__ void vector_add_gpu_3d(float *a, float *b, float *c, int nx, int ny, int nz) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    int j = blockIdx.y * blockDim.y + threadIdx.y;
    int k = blockIdx.z * blockDim.z + threadIdx.z;
    // 3 adds, 3 multiplies, 3 stores
    
    if (i < nx && j < ny && k < nz) {
        int idx = i + j * nx + k * nx * ny;
        if (idx < nx * ny * nz) {
            c[idx] = a[idx] + b[idx];
        }
    }
    // you get the point...
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2256534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用Docker轻松搭建高颜值无广告音乐播放器SPlayer随时随地听歌

前言 在快节奏的生活环境中&#xff0c;音乐成为了许多人放松和享受的重要方式。本文将介绍如何在Linux Ubuntu系统中使用Docker快速部署一款高颜值无广告的某抑云音乐播放器——SPlayer&#xff0c;并结合Cpolar内网穿透工具实现出门在外也能远程访问本地服务&#xff0c;随时…

C# Decimal

文章目录 前言1. Decimal 的基本特性2. 基本用法示例3. 特殊值与转换4. 数学运算示例5. 精度处理示例6. 比较操作示例7. 货币计算示例8. Decimal 的保留小数位数9. 处理 Decimal 的溢出和下溢10. 避免浮点数计算误差总结 前言 decimal 是 C# 中一种用于表示高精度十进制数的关键…

【理论·专业课】第三次作业

第1题&#xff08;存储管理_内存碎片&#xff09; 请指出内部碎片与外部碎片的区别&#xff61; ANS&#xff1a; 内部碎片是分配给进程但未被进程使用且无法被其他进程利用的内存空间 外部碎片是内存中因进程分配释放内存形成的不连续小块&#xff0c;虽总和够但因不连续无…

最新的springboot 3.x的支持s3协议的2.x方法的minio上传文件方法

拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/qiluo-images/minio:latest运行命令 docker run -d \--name minio \-p 10087:9000 \-p 10088:9001 \-e MINIO_ROOT_USERminioadmin \-e MINIO_ROOT_PASSWORDY6HYraaphfZ9k8Lv \-v /data/minio/data:/data \-v /data/…

cocos creator接入字节跳动抖音小游戏JSAPI敏感词检测(进行文字输入,但输入敏感词后没有替换为*号)

今天更新了某个抖音小游戏的版本&#xff0c;增加了部分剧情&#xff0c;半天过后一条短信审核未通过&#xff0c;emmm…抖音总是能给开发者惊喜…打开电脑看看这次又整什么幺蛾子… 首先是一脸懵逼&#xff0c;后端早已接入了官方的内容安全检测能力了&#xff08;https://de…

Origin快速拟合荧光寿命、PL Decay (TRPL)数据分析处理-方法二

1.先导入数据到origin 2.导入文件的时候注意&#xff1a;名字短的这个是&#xff0c;或者你打开后看哪个里面有800&#xff0c;因为我的激光重频是1.25Hz&#xff08;应该是&#xff0c;不太确定单位是KHz还是MHz&#xff09;&#xff0c;所以对应的时间是800s。 3.选中两列直接…

17. 面向对象的特征

一、面向对象的三大特征 面向对象的三大特征指的是 封装、继承、多态。 封装&#xff08;encapsulation&#xff0c;有时称为数据隐藏&#xff09;是处理对象的一个重要概念。从形式上看&#xff0c;封装就是将数据和行为组合在一个包中&#xff0c;并对对象的使用者隐藏具体的…

Apache Dolphinscheduler可视化 DAG 工作流任务调度系统

Apache Dolphinscheduler 关于 一个分布式易扩展的可视化 DAG 工作流任务调度系统。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用。 DolphinScheduler 的主要特性如下&#xff1a; 易于部署&#xff0c;提供四种部署方式&am…

第二部分:基础知识 6.函数 --[JavaScript 新手村:开启编程之旅的第一步]

JavaScript 函数是可重用的代码块&#xff0c;用于执行特定任务。函数可以接受参数&#xff08;输入数据&#xff09;&#xff0c;并且可以返回一个值。JavaScript 提供了多种定义函数的方式&#xff0c;下面将详细介绍这些方式&#xff0c;并给出一些示例。 1. 函数声明 下面…

我眼中的“懂重构”(一)

初识重构 2017年的时候&#xff0c;领导让我看公司的一本书《重构——改善代码的既有设计》&#xff0c;这是一本JAVA版本的&#xff0c;前后看了2遍。那时候看书因为不懂看的格外仔细。我只是那时候不懂&#xff0c;然而多年后的今天我仍然发现很多人对重构充满误解。在刚进入…

机器学习详解(3):线性回归之代码详解

文章目录 1 数据预处理2 构建线性回归模型并绘制回归线初始化方法前向传播&#xff1a;forward_propagation代价函数&#xff1a;cost_function反向传播&#xff1a;backward_propagation参数更新&#xff1a;update_parameters训练方法&#xff1a;train代码运行结果 3 使用Py…

基于openzeppelin插件的智能合约升级

一、作用以及优点 部署可升级合约&#xff0c;插件自动部署proxy和proxyAdmin合约&#xff0c;帮助管理合约升级和交互&#xff1b;升级已部署合约&#xff0c;通过插件快速升级合约&#xff0c;脚本开发方便快捷&#xff1b;管理代理管理员的权限&#xff0c;只有proxyAdmin的…

游戏引擎学习第36天

仓库 :https://gitee.com/mrxiao_com/2d_game 回顾之前的内容 在这个程序中&#xff0c;目标是通过手动编写代码来从头开始制作一个完整的游戏。整个过程不使用任何库或现成的游戏引擎&#xff0c;这样做的目的是为了能够全面了解游戏执行的每一个细节。开发过程中&#xff0…

试题转excel;pdf转excel;试卷转Excel,word试题转excel

一、问题描述 一名教师朋友&#xff0c;偶尔会需要整理一些高质量的题目到excel中 以往都是手动复制搬运&#xff0c;几百道题几乎需要一个下午的时间 关键这些事&#xff0c;枯燥无聊费眼睛&#xff0c;实在是看起来就很蠢的工作 就想着做一个工具&#xff0c;可以自动处理…

16-01、JVM系列之:内存与垃圾回收篇(一)

JVM系列之&#xff1a;内存与垃圾回收篇&#xff08;一&#xff09; ##本篇内容概述&#xff1a; 1、JVM结构 2、类加载子系统 3、运行时数据区之&#xff1a;PC寄存器、Java栈、本地方法栈一、JVM与JAVA体系结构 JAVA虚拟机与JAVA语言并没有必然的联系&#xff0c;它只是与特…

2030. gitLab A仓同步到B仓

文章目录 1 A 仓库备份 到 B 仓库2 B 仓库修改main分支的权限 1 A 仓库备份 到 B 仓库 #!/bin/bash# 定义变量 REPO_DIR"/home/xhome/opt/git_sync/zz_xx_xx" # 替换为你的本地库A的实际路径 REMOTE_ORIGIN"http://192.168.1.66:8181/zzkj_software/zz_xx_xx.…

服务器上部署前端页面-实现IP+端口/index.html在线访问你的网页

首先一点&#xff0c;不管是那个框架开发的网页前端&#xff0c;最后都需要Build,构建完毕以后都是原始的HTML CSS JS 三样文件&#xff01; 所以不管用原始的三剑客&#xff08;HTML CSS JS&#xff09;开发的前端还是用各类框架开发的前端界面&#xff08;只是让开发简单…

树莓派 PICO RP2040 MACOS 使用

文章参考&#xff1a; Developing in C on the RP2040: macOS | Wellys Dev 这里会提示报错&#xff1a;ln: /bin/picotool: Operation not permitted 参考&#xff1a;Mac ln命令报错&#xff1a;Operation not permitted_ln operation not permitted-CSDN博客 放在 usr/lo…

顶顶通电话机器人开发接口对接大语言模型之实时流TTS对接介绍

大语言模型一般都是流式返回文字&#xff0c;如果等全部文字返回了一次性去TTS&#xff0c;那么延迟会非常严重&#xff0c;常用的方法就是通过标点符号断句&#xff0c;返回了一句话就提交给TTS。随着流TTS的出现&#xff0c;就可以直接把大模型返回的文字灌给流TTS&#xff0…

git使用-创建本地仓库、绑定远程仓库

文章目录 1. 创建git仓库2. commit提交到本地3. 创建远程仓库4. 关联远程仓库5. push代码至远程仓库6. 完成初始化 git作为版本控制工具&#xff0c;在开发过程中经常使用到。这里以github为例&#xff0c;简单介绍下仓库的创建及绑定&#xff0c;方便忘记了能快速的想起来。 1…