单机多进程,每个进程多张卡 mpi nccl 程序设计检验

做了部分注释,比较乱

本示例结构:

1,源代码

#include <stdlib.h>
#include <stdio.h>
#include "cuda_runtime.h"
#include "nccl.h"
#include "mpi.h"
#include <unistd.h>
#include <stdint.h>
#include <sys/time.h>


#define MPI_CHECK(cmd) do {                          \
  int e = cmd;                                      \
  if( e != MPI_SUCCESS ) {                          \
    printf("Failed: MPI error %s:%d '%d'\n",        \
        __FILE__,__LINE__, e);   \
    exit(EXIT_FAILURE);                             \
  }                                                 \
} while(0)

#define CUDA_CHECK(cmd) do {                         \
  cudaError_t e = cmd;                              \
  if( e != cudaSuccess ) {                          \
    printf("Failed: Cuda error %s:%d '%s'\n",             \
        __FILE__,__LINE__,cudaGetErrorString(e));   \
    exit(EXIT_FAILURE);                             \
  }                                                 \
} while(0)

#define NCCL_CHECK(cmd) do {                         \
  ncclResult_t r = cmd;                             \
  if (r!= ncclSuccess) {                            \
    printf("Failed, NCCL error %s:%d '%s'\n",             \
        __FILE__,__LINE__,ncclGetErrorString(r));   \
    exit(EXIT_FAILURE);                             \
  }                                                 \
} while(0)

static uint64_t getHostHash(const char* string) {
  // Based on DJB2a, result = result * 33 ^ char
  uint64_t result = 5381;
  for (int c = 0; string[c] != '\0'; c++){
    result = ((result << 5) + result) ^ string[c];
  }
  return result;
}

static void getHostName(char* hostname, int maxlen) {
  gethostname(hostname, maxlen);
  for (int i=0; i< maxlen; i++) {
    if (hostname[i] == '.') {
        hostname[i] = '\0';
        return;
    }
  }
}


void print_vector(float* A, int n)
{
  for(int i=0; i<n; i++)
    printf("%.2f ", A[i]);
}

void init_dev_vectors(float* A_d, float* B_d, int n, int rank, long long seed, int dev_idx)
{
  float * A = (float*)malloc(n*sizeof(float));
  float * B = (float*)malloc(n*sizeof(float));
  //float * M = (float*)malloc(n*sizeof(float));//max[i] = max(A[i], B[i]);
  //float * S = (float*)malloc(n*sizeof(float));//sum[i] = sum(A[i], B[i]);
  srand(seed);

  for(int i=0; i<n; i++)
  {
    A[i] = (rand()%100)/100.0f;
    B[i] = (rand()%100)/100.0f;
  }

  printf("\nrank = %d, gpuid = %d, sendbuff =\n", rank, dev_idx);
  print_vector(A, n);
  printf("\n\n");
//  printf("\nrank = %d, Sum =\n", rank);  print_vector(S, n);

  cudaMemcpy(A_d, A, n*sizeof(float), cudaMemcpyHostToDevice);
  cudaMemcpy(B_d, B, n*sizeof(float), cudaMemcpyHostToDevice);

  free(A);
  free(B);
}

void get_seed(long long &seed)
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  seed = (long long)tv.tv_sec * 1000*1000 + tv.tv_usec;//only second and usecond;
  //printf("useconds:%lld\n", seed);
}

void fetch_dev_vector(float* A_d, int n, int rank, int dev_id)
{
  float* A = (float*)malloc(n*sizeof(float));
  cudaMemcpy(A, A_d, n*sizeof(float), cudaMemcpyDeviceToHost);
  printf("rank = %d,gpuid =%d recvbuff =\n", dev_id, rank);
  print_vector(A, n);
  printf("\n\n");

  free(A);
}

int main(int argc, char* argv[])
{
  int size = 16;//32*1024*1024;

  int myRank, nRanks, localRank = 0;

  //initializing MPI
  MPI_CHECK(MPI_Init(&argc, &argv));
  MPI_CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &myRank));
  MPI_CHECK(MPI_Comm_size(MPI_COMM_WORLD, &nRanks));

  //calculating localRank which is used in selecting a GPU
  uint64_t hostHashs[nRanks];
  char hostname[1024];
  getHostName(hostname, 1024);
  hostHashs[myRank] = getHostHash(hostname);
  MPI_CHECK(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, hostHashs, sizeof(uint64_t), MPI_BYTE, MPI_COMM_WORLD));
  for (int p=0; p<nRanks; p++) {
     if (p == myRank) break;
     if (hostHashs[p] == hostHashs[myRank]) localRank++;
  }

  //each process is using two GPUs
  int nDev = 2;

  float** sendbuff = (float**)malloc(nDev * sizeof(float*));
  float** recvbuff = (float**)malloc(nDev * sizeof(float*));
  cudaStream_t* s = (cudaStream_t*)malloc(sizeof(cudaStream_t)*nDev);

  //picking GPUs based on localRank
  for (int i = 0; i < nDev; ++i) {
    CUDA_CHECK(cudaSetDevice(localRank*nDev + i));
    CUDA_CHECK(cudaMalloc(sendbuff + i, size * sizeof(float)));
    CUDA_CHECK(cudaMalloc(recvbuff + i, size * sizeof(float)));
    CUDA_CHECK(cudaMemset(sendbuff[i], 1, size * sizeof(float)));
    CUDA_CHECK(cudaMemset(recvbuff[i], 0, size * sizeof(float)));
    CUDA_CHECK(cudaStreamCreate(s+i));

    long long seed = 0;
    get_seed(seed);
//void init_dev_vectors(float* A_d, float* B_d, int n, int rank, long long seed, int dev_idx)
    init_dev_vectors(sendbuff[i], recvbuff[i], size, myRank, seed, i);
  }

  ncclUniqueId id;
  ncclComm_t comms[nDev];

  //generating NCCL unique ID at one process and broadcasting it to all
  if (myRank == 0) ncclGetUniqueId(&id);
  MPI_CHECK(MPI_Bcast((void *)&id, sizeof(id), MPI_BYTE, 0, MPI_COMM_WORLD));

  //initializing NCCL, group API is required around ncclCommInitRank as it is
  //called across multiple GPUs in each thread/process
  NCCL_CHECK(ncclGroupStart());
  for (int i=0; i<nDev; i++) {
     CUDA_CHECK(cudaSetDevice(localRank*nDev + i));
     NCCL_CHECK(ncclCommInitRank(comms+i, nRanks*nDev, id, myRank*nDev + i));
  }
  NCCL_CHECK(ncclGroupEnd());

  //calling NCCL communication API. Group API is required when using
  //multiple devices per thread/process
  NCCL_CHECK(ncclGroupStart());
  for (int i=0; i<nDev; i++)
     NCCL_CHECK(ncclAllReduce((const void*)sendbuff[i], (void*)recvbuff[i], size, ncclFloat, ncclSum,
           comms[i], s[i]));
  NCCL_CHECK(ncclGroupEnd());

  //synchronizing on CUDA stream to complete NCCL communication
  for (int i=0; i<nDev; i++)
      CUDA_CHECK(cudaStreamSynchronize(s[i]));


  for(int i=0; i<nDev; i++)
    fetch_dev_vector(recvbuff[i], size, myRank, i);

  //freeing device memory
  for (int i=0; i<nDev; i++) {
     CUDA_CHECK(cudaFree(sendbuff[i]));
     CUDA_CHECK(cudaFree(recvbuff[i]));
  }

  //finalizing NCCL
  for (int i=0; i<nDev; i++) {
     ncclCommDestroy(comms[i]);
  }

  //finalizing MPI
  MPI_CHECK(MPI_Finalize());

  printf("[MPI Rank %d] Success \n", myRank);
  return 0;
}






2,构建

2.1 Makefile



LD_FLAGS := -lnccl -L/usr/local/cuda/lib64 -lcudart -I/usr/local/cuda/include

MPI_FLAGS := -I /home/hipper/ex_openmpi/local/include -L /home/hipper/ex_openmpi/local/lib -lmpi 
#-lmpi_cxx

EXE := ngpuPerProcess_mxnGPU_mProcess_oneServer
# multiProcess_multiDevice_oneServer_allreduce
# singleProcess_multiDevice_oneServer_allreduce
all: $(EXE)

ngpuPerProcess_mxnGPU_mProcess_oneServer: ngpuPerProcess_mxnGPU_mProcess_oneServer.cpp
	g++ -g $< -o $@ $(LD_FLAGS) $(MPI_FLAGS)

hello_comm: hello_comm.cpp
	g++ -g $< -o $@ $(LD_FLAGS)

.PHONY: clean
clean:
	-rm $(EXE)

2.2 构建

$ make


3,运行

$ ../../ex_openmpi/local/bin/mpirun -np 2 ./ngpuPerProcess_mxnGPU_mProcess_oneServer

4,效果

数学效果跟前文相同

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

流量预测资源总结(不断更新)

目录 整理流量预测数据集&#xff08;1&#xff09;Telecom Italia 意大利电信 2015&#xff08;2&#xff09;City Cellular Traffic Map (C2TM) 2015&#xff08;3&#xff09;、LTE Network Traffic Data_kaggle&#xff08;4&#xff09;、Cellular Traffic Analysis Data …

Python十大实用技巧【附源码】

1、什么是Python? Python简介 Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&#xff0c;其他语言的一些标点符号&#xff0c;它具有比其他语言更有特色语法结构。 …

Nacos学习思维导图

一、服务注册 参考文档&#xff1a;http://www.bryh.cn/a/118936.html https://blog.csdn.net/Saintmm/article/details/121981184 二、服务续约 参考文档&#xff1a;http://www.bryh.cn/a/118936.html https://blog.csdn.net/Saintmm/article/details/121981184 三、服务…

提取 PE 文件的各种信息

前段时间项目需要实现对 Windows PE 文件版本信息的提取&#xff0c;如文件说明、文件版本、产品名称、版权、原始文件名等信息。获取这些信息在 Windows 下当然有一系列的 API 函数供调用&#xff0c;简单方便。 我们先看一下PE文件结构&#xff0c;PE文件由DOS首部&#xff0…

FX3U-1PG使用

作为扩展模块的安装 伺服驱动器的参数设置 1.设置为0&#xff0c;为位置模式&#xff0c;发送脉冲控制&#xff1b; 2. 设置旋转方向&#xff0c;以及脉冲方式&#xff0c;通常设置为01&#xff0c;因为FX3U-1PG只支持正方向脉冲负方向脉冲方式&#xff1b; 当然想改变电机运…

基于AT89C51单片机可做实物的温度烟雾火灾报警设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/88658141?spm1001.2014.3001.5503 C 源码仿真图毕业设计实物制作步骤02 摘要 随着现代家庭用火、用电量的增加&#xff0c;家庭火灾发生的频率越来越高。火灾报警…

Cesium加载大规模三维数据渲染性能优化方案

根据实际项目经验和近期的论文&#xff0c;总结一下Cesium加载大规模三维数据性能优化方法。个人认为在实际的GIS数字孪生项目中,其可行的优化手段主要有三种&#xff1a; &#xff08;1&#xff09;通过专业的转换工具CesiumLab等对原始的三维模型进行轻量化处理&#xff0c;包…

基于ssm的自习室预订座位管理分析与实现论文

摘 要 使用旧方法对自习室预订座位管理信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在自习室预订座位管理信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次…

[鹤城杯 2021]EasyP

[鹤城杯 2021]EasyP wp 参考博客&#xff1a; basename()绕过小结 request导致的安全性问题分析 源码分析 首先进入题目&#xff0c;看到代码&#xff1a; <?php include utils.php;if (isset($_POST[guess])) {$guess (string) $_POST[guess];if ($guess $secret)…

条款16:成对使用 new 和 delete 时要采用相同形式

下面程序的行为是未定义的。至少&#xff0c;stringArray指向的100个string对象中有99个不太可能被正确地析构。 被delete的指针指向单个对象还是一个对象数组&#xff1f;内存数组通常包括数组的大小&#xff0c;delete可以知道需要调用多少个析构函数。 使用delete时使用了方…

解读 $mash 通证 “Fair Launch” 规则,将公平发挥极致

Solmash 是 Solana 生态中由社区主导的铭文资产 LaunchPad 平台&#xff0c;该平台旨在为 Solana 原生铭文项目&#xff0c;以及通过其合作伙伴 SoBit 跨链桥桥接到 Solana 的 Bitcoin 生态铭文项目提供更广泛的启动机会。有了 Solmash&#xff0c;将会有更多的 Solana 生态的铭…

最新能让老外对口型讲中文的AI 视频教程,免费开源AI工具——Wav2Lip

本期就来教大家制作海外大佬们新年祝福视频吧&#xff01;对口型视频一直在全网都非常的火爆&#xff0c;随便一个视频都是几千赞以上&#xff0c;简直堪称涨粉利器&#xff01; 是不是很有意思&#xff0c;口型完全对得上&#xff0c;表情也很自然逼真&#xff0c;不懂内行的人…

后端杂七杂八系列篇一

后端杂七杂八系列篇一 ① MySQL选择合适的数据类型① Char与Varchar② Text与Blob ② EqualsAndHashCode(callSuper true)的作用③ mybatis-plus 相关① 主键生成策略② 使用Model实现CRUD③ Wrapper的用法① Wrapper的继承关系② 项目中最常用的warpper [LambdaQueryWrapper]…

ElasticSearch数据同步

文章目录 ElasticSearch数据同步1. 同步调用2. 异步通知3. 监听binlog4. 工作中处理同步的问题 ElasticSearch数据同步 ElasticSearch中酒店数据来自于mysql数据库&#xff0c;因此MySQL数据发生改变时&#xff0c;ElasticSearch也必须跟着改变&#xff0c;这个就是ElasticSear…

轻量级性能测试工具 wrk 如何使用?

项目设计之初或者是项目快要结束的时候&#xff0c;大佬就会问我们&#xff0c;这个服务性能测试的结果是什么&#xff0c;QPS 可以达到多少&#xff0c;RPS 又能达到多少&#xff1f;接口性能可以满足未来生产环境的实际情况吗&#xff1f;有没有自己测试过自己接口的吞吐量&a…

Node.js+Express 获取前端get请求参数值

前端请求&#xff1a; http://localhost:3002/api/user/login?username002&password002 后端响应 router.get(/api/user/login, (req, res) > {let username req.query.username;let password req.query.password;const sqlStr SELECT * FROM sys_user where use…

UI自动化测试框架搭建

今天给大家分享一个seleniumtestngmavenant的UI自动化&#xff0c;可以用于功能测试&#xff0c;也可按复杂的业务流程编写测试用例&#xff0c;今天此篇文章不过多讲解如何实现CI/CD&#xff0c;只讲解自己能独立搭建UI框架&#xff0c;需要阅读者有一定的java语言基础&#x…

西北工业大学计算机组成原理实验报告——verilog前两次

说明 为了有较好的可读性&#xff0c;报告仅仅粘贴关键代码。该PDF带有大纲功能&#xff0c;点击大纲中的对应标题&#xff0c;可以快速跳转。 实验目标 掌握单周期CPU执行指令的流程和原理&#xff1b;学习使用verilog HDL语言实现单周期CPU, 并通过功能仿真&#xff1b;提…

【BIAI】Lecture2-Visual system

Lecture 2 - Visual System 专业术语 central nervous system(CNS) 中枢神经系统 pupil 瞳孔 iris 虹膜 cornea 角膜 retina 视网膜 fovea 中央凹 或 黄斑区 kens 晶状体 optic nerve 视神经 Bipolar cells 双极细胞 Ganglion cells 神经节细胞 rods 杆状细胞 cones 锥状细胞 …

uniapp中组件库的Textarea 文本域的丰富使用方法

目录 #平台差异说明 #基本使用 #字数统计 #自动增高 #禁用状态 #下划线模式 #格式化处理 API #List Props #Methods #List Events 文本域此组件满足了可能出现的表单信息补充&#xff0c;编辑等实际逻辑的功能&#xff0c;内置了字数校验等 注意&#xff1a; 由于…
最新文章