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

news2024/11/15 8:08:41

做了部分注释,比较乱

本示例结构:

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.coloradmin.cn/o/1353698.html

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

相关文章

MySQL的基础架构之内部执行过程

MySQL的逻辑架构图 如上图所示&#xff0c;MySQL可以分为Server层和存储引擎层两部分&#xff1a; 1&#xff09;Server层涵盖了MySQL的大多数核心服务功能&#xff0c;以及所有的内置函数&#xff08;如日期、时间、数学和加密函数等&#xff09;&#xff0c;所有跨存储引擎…

Javaweb之Mybatis的基础操作的详细解析

1. Mybatis基础操作 学习完mybatis入门后&#xff0c;我们继续学习mybatis基础操作。 1.1 需求 需求说明 通过分析以上的页面原型和需求&#xff0c;我们确定了功能列表&#xff1a; 查询 根据主键ID查询 条件查询 新增 更新 删除 根据主键ID删除 根据主键ID批量删除 …

腾讯云轻量应用服务器详细介绍_2024年更新

腾讯云轻量应用服务器开箱即用、运维简单的轻量级云服务器&#xff0c;CPU内存带宽配置高并且价格特别便宜&#xff0c;大带宽&#xff0c;但是限制月流量。轻量2核2G3M带宽62元一年、2核2G4M优惠价118元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;756元3年、…

数据库应用课程学生表、课程表、选课表mysql语句实战练习

1、创建表结构 目录 1、创建表结构 1.1 创建学生表 1.2 创建课程表 1.3创建选课表 1.4 插入学生表 1.5 插入课程表 1.6 插入选课表 2.以下布置操作是根据以上建立的三张表格基础上进行mysql语句的练习 2.1 查询学生信息并添加入新表 2.1.1 查询全体学生的学号与姓名&#…

ECharts配置个性化图表:圆环、立体柱状图

官网调试地址&#xff1a;调试 效果图&#xff1a; 配置&#xff1a; option {color: [#29BEFF, #A2DC00, #FFC400, #FF7F5C, #CA99FC],// 提示窗tooltip: {trigger: item,show: false},// 图例legend: {top: 5%,left: center,show: false},// 数据series: [{name: Access …

23年中科院1区算法|开普勒优化算法原理及其利用(Matlab/Python)

CEC2017中的测试 本文作者将介绍一个2023年发表在中科院1区期刊《Knowledge -Based Systems》上的优化算法——开普勒优化算法(Kepler optimization algorithm&#xff0c;KOA)[1] 算法性能上&#xff0c;与鹈鹕、黏菌、灰狼和鲸鱼等一众优化算法在CEC2014、CEC2017、CEC2020和…

SRC中的一些信息收集姿势

目录 前言 搜索引擎 Google、bing、baidu Fofa、360q、鹰图 提炼图标 提炼标题 提炼Body 提炼特殊路由 提炼特殊服务 GIT提炼 总结 本文由掌控安全学院 - 杳若 投稿 前言 前前后后挖了四个月的EDUSRC&#xff0c;顺利从路人甲升到了网络安全专家&#xff0c;从提交…

技术扫盲:如何优雅的使用 java -jar

java -jar xxx.jar java -jar 是一个用于在命令行界面中执行 Java 可执行 JAR 文件的命令。它的语法如下&#xff1a; java -jar <JAR 文件路径> [参数]其中&#xff1a; java 是 Java 运行时环境的可执行文件。-jar 是一个选项&#xff0c;表示要执行的文件是一个 JA…

南昌本地人才招聘网站有哪些

南昌吉鹿力招聘网是一家南昌本地人才招聘网站&#xff0c;真正专属于年轻人的移动社交招聘平台&#xff0c;提供职业档案、人脉、求职、聊天等功能。主要优点是扩大招聘渠道&#xff0c;通过社区招聘平台找到工作机会&#xff0c;并为用户提供职业建议和职位发布等服务。 吉鹿…

技术资讯:Vue 3.4 新版本发布,1分钟快速看看改了啥!

大家好&#xff0c;我是大澈&#xff01; 本文约1000字&#xff0c;整篇阅读大约需要1分钟。 感谢关注微信公众号&#xff1a;“程序员大澈”&#xff0c;免费领取"面试礼包"一份&#xff0c;然后免费加入问答群&#xff0c;从此让解决问题的你不再孤单&#xff01…

【办公软件】修改U盘的默认盘符

在工作中我们可能会因为有一些大型软件设置了库文件路径&#xff08;如Z盘&#xff09;。在家办公时通过U盘的方式将库拷入在U盘中&#xff0c;但是到家里的电脑上&#xff0c;U盘插入后会默认一个盘符&#xff08;如E盘&#xff09;&#xff0c;那么应该怎么操作呢&#xff1f…

【HBase】——安装部署

1 规划&前提 Zookeeper 、HDFS 正常部署规划如下 2 解压并重命名 cd /opt/software/ tar -zxvf hbase-2.4.11-bin.tar.gz -C /opt/module/ cd /opt/module mv hbase-2.4.11/ hbase3 修改配置文件 3.1 hbase-env.sh #!/usr/bin/env bash # #/** # * Licensed to the Apa…

你可能不知道的5款好用封面设计工具,快来一探究竟吧!

我相信每个作者和出版商都希望在一部作品完成后有一个醒目的封面&#xff0c;这样潜在的读者就会有足够的好奇心拿起这本书&#xff0c;你的书的销量就会上升。这就是封面设计软件的使用&#xff0c;专业的封面设计软件可以增加前沿效果&#xff0c;呈现最适合书籍内容的创意布…

UniversalTransformer with Adaptive Computation Time(ACT)

原论文链接&#xff1a;https://arxiv.org/abs/1807.03819 Main code import torch import numpy as npclass PositionTimestepEmbedding(torch.nn.Module):def forward(self, x, t):device x.devicesequence_length x.size(1)d_model x.size(2)position_embedding np.arr…

(学习打卡2)重学Java设计模式之六大设计原则

前言&#xff1a;听说有本很牛的关于Java设计模式的书——重学Java设计模式&#xff0c;然后买了(*^▽^*) 开始跟着小傅哥学Java设计模式吧&#xff0c;本文主要记录笔者的学习笔记和心得。 打卡&#xff01;打卡&#xff01; 六大设计原则 &#xff08;引读&#xff1a;这里…

AIGC带给开发者的冲击

未来会有两种开发者&#xff0c;一种是会使用AIGC工具的开发者另一种是不会使用AIGC的开发者&#xff0c;AIGC的出现提高了开发效率和代码质量&#xff0c;对开发者意味着需要不断学习和适应新的技术和工作范式&#xff0c;开发者可以把更多的精力放在高级抽象的定义以及更高维…

(16)Linux 进程等待 wait/waitpid 的 status 参数

前言&#xff1a;我们开始讲解进程等待&#xff0c;简单地讲解 wait 函数&#xff0c;然后我们主要讲解 waitpid 函数。由于 wait 只有一个参数 status&#xff0c;且 waitpid 有三个参数且其中一个也是 status&#xff0c;我们本章重点讲解这个 status 参数。 一、进程等待&a…

学习笔记240102 --- 表单无法输入,是否data中没有提前声明导致的

前端框架 &#xff1a;vue2.x 第三方ui组件&#xff1a;ElementUI 操作系统&#xff1a;windows 浏览器&#xff1a;chrome 谷歌 问题描述 表单使用中&#xff0c;没有在data中提前声明参数&#xff0c;当数据回显时&#xff0c;表单无法输入 <el-form :model"queryPa…

Oracle-数据库迁移之后性能变慢问题分析

问题背景&#xff1a; ​一套Oracle11.2.0.4的RAC集群&#xff0c;通过Dataguard switchover方式迁移到新机器之后&#xff0c;运行第一天应用报障说应用性能慢&#xff0c;需要进行性能问题排查 问题分析&#xff1a; 首先&#xff0c;登陆到服务器&#xff0c;用TOP看一眼两个…

CMake入门教程【基础篇】CMake+Linux gcc构建C++项目

文章目录 1.概述2.GCC与CMake介绍3.安装CMake和GCC4.代码示例 1.概述 在Linux环境下&#xff0c;使用CMake结合GCC&#xff08;GNU Compiler Collection&#xff09;进行项目构建是一种常见且高效的方法。CMake作为一个跨平台的构建系统&#xff0c;可以生成适用于不同编译器的…