cuda lib 线程安全的要义

news2024/11/27 11:43:20

1, 概述

cuda lib 线程安全的几个多线程的情景:

单卡多线程;

多卡多线程-每卡单线程;

多卡多线程-每卡多线程;

需要考虑的问题:


每个 cublasHandle_t 只能有一个stream么?
每个cusolverHandle_t 只能有一个 stream么?
每个cusolverHandle_t只能有要给cublasHandle_t么?
多个线程同时跑在多个或一个gpu上,需要使用多个stream么?都是NULL 默认stream的话,不会影响效率吧?

2, 多线程示例

从如下代码思考开去,这个多线程场景是使用了openmp自动划分任务,也可以使用pthread来七分任务,这里对这个示例进行了注释:

https://github.com/NVIDIA/cuda-samples/blob/v11.4/Samples/cudaOpenMP/cudaOpenMP.cu




/*
 * Multi-GPU sample using OpenMP for threading on the CPU side
 * needs a compiler that supports OpenMP 2.0
 */
//使用openmp时包含其头文件
#include <omp.h>
#include <stdio.h>  // stdio functions are used since C++ streams aren't necessarily thread safe
//#include <helper_cuda.h>

#define checkCudaErrors(val)  val

using namespace std;

// a simple kernel that simply increments each array element by b
__global__ void kernelAddConstant(int *g_a, const int b)
{
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    g_a[idx] += b;
}

// a predicate that checks whether each array element is set to its index plus b
int correctResult(int *data, const int n, const int b)
{
    for (int i = 0; i < n; i++)
        if (data[i] != i + b)
            return 0;

    return 1;
}

int main(int argc, char *argv[])
{
    int num_gpus = 0;   // number of CUDA GPUs

    printf("%s Starting...\n\n", argv[0]);

    /
    // determine the number of CUDA capable GPUs
    //
    cudaGetDeviceCount(&num_gpus);

    if (num_gpus < 1)
    {
        printf("no CUDA capable devices were detected\n");
        return 1;
    }

    /
    // display CPU and GPU configuration
    //
    printf("number of host CPUs:\t%d\n", omp_get_num_procs());
    printf("number of CUDA devices:\t%d\n", num_gpus);

    for (int i = 0; i < num_gpus; i++)
    {
        cudaDeviceProp dprop;
        cudaGetDeviceProperties(&dprop, i);
        printf("   %d: %s\n", i, dprop.name);
    }

    printf("---------------------------\n");


    /
    // initialize data
    //
    unsigned int n = num_gpus * 8192;
    unsigned int nbytes = n * sizeof(int);// nbytes = num_gpus * [8192*sizeof(int)]
    printf("nbytes=%u\n", nbytes);
    int *a = 0;     // pointer to data on the CPU
    int b = 3;      // value by which the array is incremented
    a = (int *)malloc(nbytes);

    if (0 == a)
    {
        printf("couldn't allocate CPU memory\n");
        return 1;
    }
//这里如果使用 #pragma omp parallel for 的话,会不会影响下面的线程数?
    for (unsigned int i = 0; i < n; i++)
        a[i] = i;


    
    // run as many CPU threads as there are CUDA devices
    //   each CPU thread controls a different device, processing its
    //   portion of the data.  It's possible to use more CPU threads
    //   than there are CUDA devices, in which case several CPU
    //   threads will be allocating resources and launching kernels
    //   on the same device.  For example, try omp_set_num_threads(2*num_gpus);
    //   Recall that all variables declared inside an "omp parallel" scope are
    //   local to each CPU thread
    //
    // 通过获知GPU的数量来设定下面参与工作的线程数量
    omp_set_num_threads(num_gpus);  // create as many CPU threads as there are CUDA devices
    //omp_set_num_threads(2*num_gpus);// create twice as many CPU threads as there are CUDA devices
    //自动创建 num_gpus 个线程
    #pragma omp parallel
    {
        //每个线程获得自己的线程号,从0开始计数
        unsigned int cpu_thread_id = omp_get_thread_num();
        //获取 openmp 自动创建的总的线程数
        unsigned int num_cpu_threads = omp_get_num_threads();
	    printf("cpu_thread_id=%u   num_cpu_threads=%u\n", cpu_thread_id, num_cpu_threads);

        // set and check the CUDA device for this CPU thread
        int gpu_id = -1;
        //两个或以上的线程,可以同时使用同一个 gpu 设备;cudaSetDevice(id) 会使得本线程锁定这个 id-th gpu 设备,接下来发生的cudaXXX,都是在这个gpu上发生的。
        checkCudaErrors(cudaSetDevice(cpu_thread_id % num_gpus));   // "% num_gpus" allows more CPU threads than GPU devices
        checkCudaErrors(cudaGetDevice(&gpu_id));//这个函数仅仅返回本线程锁定的gpu的id。
        printf("CPU thread %d (of %d) uses CUDA device %d, set id=%d, get id = %d\n", cpu_thread_id, num_cpu_threads, gpu_id, cpu_thread_id%num_gpus, gpu_id);

        int *d_a = 0;   // pointer to memory on the device associated with this CPU thread
        //下面找到本线程需要处理的数据起始地址
        int *sub_a = a + cpu_thread_id * n / num_cpu_threads;   // pointer to this CPU thread's portion of data
        unsigned int nbytes_per_kernel = nbytes / num_cpu_threads;//其中的 nbytes = num_gpus * [8192*sizeof(int)], 是整除关系;得到每个线程需要分配的显存字节数
        dim3 gpu_threads(128);  // 128 threads per block
        dim3 gpu_blocks(n / (gpu_threads.x * num_cpu_threads));// n = num_gpus * 8192;   其中 8192 是128的整数倍, num_cpu_threads 是 num_gpus 的小小的整数倍; 
        // 这样每个block含128个线程; 每个线程需要几个block呢 = n/(gpu_threads.x * num_cpu_threads)

        checkCudaErrors(cudaMalloc((void **)&d_a, nbytes_per_kernel));//在本线程所setDevice的gpu上cudaMalloc显存空间;
        checkCudaErrors(cudaMemset(d_a, 0, nbytes_per_kernel));//将分的的空间刷0
        // 将本线程需要处理的数据块拷贝的本线程所cudaMalloc的显存中;
        checkCudaErrors(cudaMemcpy(d_a, sub_a, nbytes_per_kernel, cudaMemcpyHostToDevice));
        //本线程启动kernel,处理自己的显存的数据;
        kernelAddConstant<<<gpu_blocks, gpu_threads>>>(d_a, b);
        // 本线程将处理好的数据拷贝到本线程负责的系统内存块中
        checkCudaErrors(cudaMemcpy(sub_a, d_a, nbytes_per_kernel, cudaMemcpyDeviceToHost));
        //释放显存
        checkCudaErrors(cudaFree(d_a));

    }
    printf("---------------------------\n");

    if (cudaSuccess != cudaGetLastError())
        printf("%s\n", cudaGetErrorString(cudaGetLastError()));


    
    // check the result
    //对计算结果进行对比
    bool bResult = correctResult(a, n, b);

    if (a)
        free(a); // free CPU memory

    exit(bResult ? EXIT_SUCCESS : EXIT_FAILURE);
}




运行效果:


要保证cuda lib的线程安全,首先确定cuda driver cuda runtime 都是线程安全的,这个其实是没有问题的,也就是说多个线程多块显卡同时运行的场景是不会引发cuda runtime的线程安全问题的,这点可以放心;

3, 多线程安全分析

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

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

相关文章

SpringBoot+SSM项目实战 苍穹外卖(4) day4作业

继续上一节的内容&#xff0c;本节是作业课程&#xff0c;要求独立完成套餐管理模块所有业务功能&#xff0c;包括&#xff1a;新增套餐、套餐分页查询、删除套餐、修改套餐、起售停售套餐。 目录 新增套餐根据分类id查询菜品功能新增套餐功能 套餐分页查询删除套餐根据id查询套…

2023年8月14日 Go生态洞察:向后兼容性、Go 1.21与Go 2

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

echarts中option个参数的含义

var option {title: {text: ECharts 入门示例},tooltip: {},legend: {data: [数量]},xAxis: {data: [衬衫, 羊毛衫, 雪纺衫, 裤子, 高跟鞋, 袜子]},yAxis: {},series: [{name: 数量,type: bar,data: [5, 20, 36, 10, 10, 20]}] }; title&#xff1a;主要控制图表的标题 legen…

python-04(入门基础篇4——lists相关的部分语法)

python-04&#xff08;入门基础篇4——lists相关的部分语法&#xff09; 1. 前言1.1 python入门1.2 参考官网 2. 关于索引和切片3. 在列表追加元素3.1 支持拼接3.2 使用list.append() 方法在列表末尾添加新项 4. 列表是可变类型4.1 更改其中某元素内容4.2 使用切片更改列表大小…

el-table-column 添加 class类

正常添加class 发现没有效果 class"customClass" 发现并没有添加上去 看了一下官网发现 class-name 可以实现 第一步: :class-name"customClass" 第二步 : customClass: custom-column-class, 然后就发现可以了

数据中心:保障企业运营安全可靠的关键

随着人工智能与云计算的爆发&#xff0c;数据中心行业迎来了前所未有的需求增长。然而&#xff0c;这也带来了一系列的挑战。各地政府机构对数据中心建设出台了更为完善和严格的地方标准&#xff0c;企业面临着运营成本高、人才短缺和节能减排等困难。同时&#xff0c;过去频频…

Shrio 安全框架

目录 前言 1.介绍 2.整合 Shiro 到 Spring Boot 3.Shiro 相关配置 总结 前言 几乎所有涉及用户的系统都需要进行权限管理&#xff0c;权限管理涉及到一个系统的安全。Spring Boot 的安全框架整合方案中还有一个璀璨的明珠&#xff1a;Shrio。 1.介绍 Shiro是一款由Java 编…

除了Microsoft的账户密码之外,PIN也有满满的“安全感”,不复杂却更安全

本文介绍如何在Windows 11上更改你的PIN。本说明适用于所有Windows 11电脑&#xff0c;不考虑制造商&#xff08;戴尔、惠普、联想等&#xff09;。 如何在Windows 11上更改PIN 按照以下步骤在Windows 11上更改或创建电脑的PIN&#xff1a; 1、打开Windows设置。右键单击任务…

节省时间,提高效率:深入解析MyBatis Plus

1. MyBatis Plus 概述 将Mybatis 通用Mapper PageHelper 升级成 MyBatis Plus 1.1 简介 官网&#xff1a;https://baomidou.com/ 参考教程&#xff1a;https://baomidou.com/pages/24112f/ MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#…

记录 | 使用samba将ubuntu文件夹映射到windows实现共享文件夹

一、ubuntu配置 1. 安装 samba samba 是在 Linux 和 UNIX 系统上实现 SMB 协议的一个免费软件&#xff0c;由服务器及客户端程序构成。SMB&#xff08;Server Messages Block&#xff0c;信息服务块&#xff09;是一种在局域网上共享文件和打印机的一种通信协议。 sudo apt-…

解决 Xshell 无法使用 root 账户远程登录 Linux 的问题

文章目录 问题描述问题原因解决办法 笔者出问题时的运行环境&#xff1a; Red Hat Enterprise Linux 9.2 x86_64 Xshell 7 问题描述 笔者在新安装的 Red Hat Enterprise Linux 中发现一个问题。在 RHEL 安装完之后&#xff0c;无法在 Xshell 中使用 root 账户远程登录此 Lin…

光学式雨量监测站-雨量监测的得力助手

随着科技的发展&#xff0c;人们对天气的预测和监测越来越依赖现代化的设备。光学式雨量监测站作为一种雨量监测仪器&#xff0c;能够实现对降雨量的测量&#xff0c;为天气预报和气候研究提供数据支持。 一、光学式雨量监测站的工作原理 WX-YJ3 光学式雨量监测站主要利用光学…

软件测试卷王的自述,我难道真的很卷?

前言 前段时间去面试了一个公司&#xff0c;成功拿到了offer&#xff0c;薪资也从12k涨到了18k&#xff0c;对于工作都还没两年的我来说&#xff0c;还是比较满意的&#xff0c;毕竟一些工作3、4年的可能还没我高。 我可能就是大家说的卷王&#xff0c;感觉自己年轻&#xff…

探索AIGC未来:CPU源码优化、多GPU编程与中国算力瓶颈与发展

★人工智能&#xff1b;大数据技术;AIGC;Turbo;DALLE 3;多模态大模型&#xff1b;MLLM&#xff1b;LLM&#xff1b;Agent&#xff1b;Llama2&#xff1b;国产GPU芯片&#xff1b;GPU;CPU&#xff1b;高性能计算机&#xff1b;边缘计算&#xff1b;大模型显存占用&#xff1b;5G…

今日问题:解决最新Chrome和chromedriver版本对不上的问题

from selenium import webdriver #from .chrome.webdriver import WebDriver as Chrome from selenium.webdriver.common.by import By from time import sleep driver webdriver.Chrome()driver.get("https://www.baidu.com/") driver.maximize_window()#窗口最大化…

英文论文查重复率网址

大家好&#xff0c;今天来聊聊英文论文查重复率网址&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 英文论文查重复率网址 在撰写英文论文时&#xff0c;查重是确保论文原创性和质量的重要环节快码论文…

01.项目简介

开源数字货币交易所&#xff0c;基于Java开发的货币交易所 | BTC交易所 | ETH交易所 | 数字货币交易所 | 交易平台 | 撮合交易引擎。本项目基于SpringCloudAlibaba微服务开发&#xff0c;可用来搭建和二次开发数字货币交易所。 项目特色&#xff1a; 基于内存撮合引擎&#xf…

快速实现入门HarmonyOS开发

本文档适用于HarmonyOS应用开发的初学者。编写两个简单的页面&#xff0c;实现在第一个页面点击按钮跳转到第二个页面。开始前&#xff0c;请参考下载与安装软件、配置开发环境和运行HelloWorld&#xff0c;完成开发工具的安装和开发环境的配置。 开发Ability 概述&#xff1…

ZStack Cloud构建青州市中医院核心业务云平台

青州市中医院通过ZStack Cloud云平台构建云基础设施&#xff0c;实现对原有物理机和分布式存储平台的利旧和纳管&#xff0c;有效将HIS&#xff08;医院管理系统&#xff09;、PACS&#xff08;影像系统&#xff09;等核心业务系统进行统一管理&#xff1b;同时&#xff0c;借助…

批量AI人工智能写作软件下载【2024最新】

在当今数字化的浪潮中&#xff0c;人工智能技术为各行各业带来了颠覆性的变革。其中&#xff0c;AI在文案创作领域的应用尤为引人瞩目&#xff0c;而批量AI人工智能写作更是成为文案创作者们关注的热点。本文将深入探讨批量AI人工智能写作的概念、其在不同领域的应用&#xff0…