GeminiGraph:Graph.hpp中Graph类的init()函数详解

 应用程序算法在使用GeminiGraph框架时,首先通过构造器进行Graph类的实例化,实例化过程中具体Gemini做了哪些工作,下面来逐行进行介绍。

//构造器
  Graph() {
    threads = numa_num_configured_cpus();      //返回系统中cpu的数量
    sockets = numa_num_configured_nodes();     //返回系统中内存节点的数量
    threads_per_socket = threads / sockets;    //表示每个cpu分到的内存节点数

    init();
  }

init()初始化中主要进行了numa相关的初始化,omp相关的初始化,MPI相关的初始化操作。

接下来逐行地详细介绍每一段代码的含义。

  void init() {
    edge_data_size = std::is_same<EdgeData, Empty>::value ? 0 : sizeof(EdgeData);
    unit_size = sizeof(VertexId) + edge_data_size;
    edge_unit_size = sizeof(VertexId) + unit_size;

    assert( numa_available() != -1 );
    assert( sizeof(unsigned long) == 8 ); // assume unsigned long is 64-bit

    char nodestring[sockets*2+1];
    nodestring[0] = '0';
    for (int s_i=1;s_i<sockets;s_i++) {
      nodestring[s_i*2-1] = ',';
      nodestring[s_i*2] = '0'+s_i;
    }
    struct bitmask * nodemask = numa_parse_nodestring(nodestring);
    numa_set_interleave_mask(nodemask);

    omp_set_dynamic(0);
    omp_set_num_threads(threads);
    thread_state = new ThreadState * [threads];
    local_send_buffer_limit = 16;
    local_send_buffer = new MessageBuffer * [threads];
    for (int t_i=0;t_i<threads;t_i++) {
      thread_state[t_i] = (ThreadState*)numa_alloc_onnode( sizeof(ThreadState), get_socket_id(t_i));
      local_send_buffer[t_i] = (MessageBuffer*)numa_alloc_onnode( sizeof(MessageBuffer), get_socket_id(t_i));
      local_send_buffer[t_i]->init(get_socket_id(t_i));
    }
    #pragma omp parallel for
    for (int t_i=0;t_i<threads;t_i++) {
      int s_i = get_socket_id(t_i);
      assert(numa_run_on_node(s_i)==0);
      #ifdef PRINT_DEBUG_MESSAGES
      // printf("thread-%d bound to socket-%d\n", t_i, s_i);
      #endif
    }
    #ifdef PRINT_DEBUG_MESSAGES
    // printf("threads=%d*%d\n", sockets, threads_per_socket);
    // printf("interleave on %s\n", nodestring);
    #endif

    MPI_Comm_rank(MPI_COMM_WORLD, &partition_id);
    MPI_Comm_size(MPI_COMM_WORLD, &partitions);
    send_buffer = new MessageBuffer ** [partitions];
    recv_buffer = new MessageBuffer ** [partitions];
    for (int i=0;i<partitions;i++) {
      send_buffer[i] = new MessageBuffer * [sockets];
      recv_buffer[i] = new MessageBuffer * [sockets];
      for (int s_i=0;s_i<sockets;s_i++) {
        send_buffer[i][s_i] = (MessageBuffer*)numa_alloc_onnode( sizeof(MessageBuffer), s_i);
        send_buffer[i][s_i]->init(s_i);
        recv_buffer[i][s_i] = (MessageBuffer*)numa_alloc_onnode( sizeof(MessageBuffer), s_i);
        recv_buffer[i][s_i]->init(s_i);
      }
    }
    alpha = 8 * (partitions - 1);
    MPI_Barrier(MPI_COMM_WORLD);
  }
  • 2-4:分别是表示顶点数据大小,一个顶点一条边的数据大小,一个顶点两条边的大小。EdgeData为调用graph时传入的类型,sizeof(Empty)==1;VertexId是unsigned(默认为int)类型。edge_unit_size为一个顶点两条边的大小。
  • 6-7:assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。numa_available(): 判断你电脑支持不支持numa, 不过貌似linux 2.4以后的都支持;
  • 9-16: Graph()构造器中定义sockets = numa_num_configured_nodes();即系统中内存节点的数量。nodestring为"0,1,2,3,4,5,.......,sockets-2,sockets-1,sockets"的递增字符串。
  • 15:nodemask 是通过解析节点的字符串列表变成的一个位掩码。
  • 16:Numa_set_interleave_mask()将当前任务的内存交错掩码设置为nodemask。所有新的内存分配都在交错掩码中的所有节点上进行分页交错。
  • 18:omp_set_dynamic(0);不进行动态分配当前线程组(team)的线程数量。
  • 19:在串行代码区调用omp_set_num_threads来设置当前线程组(team)的线程数量
  • 20-27:内存分配
  • 24,25:Numa_alloc_onnode()在指定的节点上分配内存。size参数将被四舍五入到系统页面大小的倍数。get_socket_id()获取内存节点号
  • 28-35:检查每个threads上的内存节点是否分配成功
  • 31:Numa_run_on_node()在特定节点上运行当前任务及其子任务。
  • 41:获取当前并行进程号并赋值给partition_id
  • 42:获取并行进程数量并赋值给partitions
  • 43-54:通信数组的初始化; MessageBuffer* [partitions] [sockets]; numa-aware;三维数组。
  • 56:用于一个通信子中所有进程的同步,调用函数时进程将处于等待状态,直到通信子中所有进程 都调用了该函数后才继续执行。

其中Server cluster 是服务器集群,例如超算中心;

服务器集群中有多个服务器,比如一台主机 ,即上图中的partition,MPI中获取到的并行进程数量和服务器数量相同,partitions的数值就是服务器集群中服务器的数量;

一个服务器(主机)中有多个槽,即 numa_num_configured_nodes() 返回的系统中槽的数量,也就是sockets;

每一个槽中有多个核心(core),即numa_num_configured_cpus() 返回的系统中core的数量,也就是threads。

由此构建的MessageBuffer [partitions] [sockets] [threads]; numa-aware;三维数组。

本人是小菜鸟一枚,如有错误,欢迎在评论区讨论。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值