Gemini图计算框架中提供的例子之bfs
这是gemini中的bfs例子,我写了些注释,但是有些东西不太懂,希望有人看到,指导一下,主要是忙信号的函数里面的dst变量,是不是激活节点的邻居,它的源代码没有看得太仔细,所以一些东西还不会,希望把那几个例子看了。
有一些好的图计算论文欢迎推荐。
#include <stdio.h>
#include <stdlib.h>
#include "core/graph.hpp"
void compute(Graph<Empty> * graph, VertexId root) {
double exec_time = 0;
exec_time -= get_time();
//记录全部节点的属性值
VertexId * parent = graph->alloc_vertex_array<VertexId>();
//记录访问过的节点
VertexSubset * visited = graph->alloc_vertex_subset();
//迭代开始时激活节点
VertexSubset * active_in = graph->alloc_vertex_subset();
//迭代结束后激活节点
VertexSubset * active_out = graph->alloc_vertex_subset();
visited->clear();
//记录root为访问过
visited->set_bit(root);
active_in->clear();
//设置root为激活节点
active_in->set_bit(root);
//设置parent全为最大值
graph->fill_vertex_array(parent, graph->vertices);
//为root节点设置属性值
parent[root] = root;
//活跃节点数为1,即root
VertexId active_vertices = 1;
for (int i_i=0;active_vertices>0;i_i++) {
//活跃节点数输出
if (graph->partition_id==0) {
printf("active(%d)>=%u\n", i_i, active_vertices);
}
active_out->clear();
//边处理
active_vertices = graph->process_edges<VertexId,VertexId>(
//空闲信号函数
[&](VertexId src){
//发送空闲信号,第一个参数为发送源,第二个为发送信息
graph->emit(src, src);
},
//空闲信号的槽函数,信号源、信号内容、信号源的邻居
[&](VertexId src, VertexId msg, VertexAdjList<Empty> outgoing_adj){
//激活的节点数
VertexId activated = 0;
//遍历出度邻居节点
for (AdjUnit<Empty> * ptr=outgoing_adj.begin;ptr!=outgoing_adj.end;ptr++) {
VertexId dst = ptr->neighbour;
//没有访问的节点进行访问,并修改parent和下一轮迭代的激活
if (parent[dst]==graph->vertices && cas(&parent[dst], graph->vertices, src)) {
active_out->set_bit(dst);
activated += 1;
}
}
//返回本轮激活的节点数
return activated;
},
//忙信号 这里的dst 我认为是激活节点的邻居。。。我也不太清楚。。。
[&](VertexId dst, VertexAdjList<Empty> incoming_adj) {
if (visited->get_bit(dst)) return;
//如果没有访问过,寻找其邻居节点,当邻居节点为激活节点时发送信号,并退出
for (AdjUnit<Empty> * ptr=incoming_adj.begin;ptr!=incoming_adj.end;ptr++) {
VertexId src = ptr->neighbour;
if (active_in->get_bit(src)) {
graph->emit(dst, src);
break;
}
}
},
[&](VertexId dst, VertexId msg) {
//设置为激活节点
if (cas(&parent[dst], graph->vertices, msg)) {
active_out->set_bit(dst);
return 1;
}
return 0;
},
active_in, visited
);
//修改visited 这里的激活节点数和边处理的返回值应该是一样的吧?
active_vertices = graph->process_vertices<VertexId>(
[&](VertexId vtx) {
visited->set_bit(vtx);
return 1;
},
active_out
);
//更新激活节点
std::swap(active_in, active_out);
}
exec_time += get_time();
if (graph->partition_id==0) {
printf("exec_time=%lf(s)\n", exec_time);
}
//聚集函数,通过MPI Send和Recv函数实现parent的同步,同步到进程0中
graph->gather_vertex_array(parent, 0);
//0号进程通过parent统计dfs遍历的结果
if (graph->partition_id==0) {
VertexId found_vertices = 0;
for (VertexId v_i=0;v_i<graph->vertices;v_i++) {
if (parent[v_i] < graph->vertices) {
found_vertices += 1;
}
}
printf("found_vertices = %u\n", found_vertices);
}
graph->dealloc_vertex_array(parent);
delete active_in;
delete active_out;
delete visited;
}
int main(int argc, char ** argv) {
MPI_Instance mpi(&argc, &argv);
if (argc<4) {
printf("bfs [file] [vertices] [root]\n");
exit(-1);
}
Graph<Empty> * graph;
graph = new Graph<Empty>();
VertexId root = std::atoi(argv[3]);
graph->load_directed(argv[1], std::atoi(argv[2]));
compute(graph, root);
for (int run=0;run<5;run++) {
compute(graph, root);
}
delete graph;
return 0;
}