void spmv_mult( GlobalAddress<Graph<PagerankVertex>> _g, vindex vx, vindex vy ) { call_on_all_cores([_g]{ g = _g; }); CHECK( vx < (1<<3) && vy < (1<<3) ); // forall rows forall<&mmjoiner>(g, [vx,vy](int64_t i, PagerankVertex& v){ auto weights = v->weights; auto origin = mycore(); mmjoiner.enroll(v.nadj); struct { int64_t i:44; vindex x:2, y:2; Core origin:16; } p = { i, vx, vy, origin }; forall<async,nullptr>(adj(g,v), [weights,p](int64_t localj, GlobalAddress<PagerankVertex> vj){ auto vjw = weights[localj]; delegate::call<async,nullptr>(vj, [vjw,p](PagerankVertex& vj){ auto yaccum = vjw * vj->v[p.x]; delegate::call<async,nullptr>(g->vs+p.i,[yaccum,p](PagerankVertex& vi){ vi->v[p.y] += yaccum; mmjoiner.send_completion(p.origin); }); }); }); }); }
void bfs(GlobalAddress<G> _g, int nbfs, TupleGraph tg) { bool verified = false; double t; auto _frontier = GlobalBag<VertexID>::create(_g->nv); auto _next = GlobalBag<VertexID>::create(_g->nv); call_on_all_cores([=]{ frontier = _frontier; next = _next; g = _g; }); // do BFS from multiple different roots and average their times for (int root_idx = 0; root_idx < nbfs; root_idx++) { // intialize parent to -1 forall(g, [](G::Vertex& v){ v->init(); v->level = -1; }); VertexID root; if (FLAGS_max_degree_source) { forall(g, [](VertexID i, G::Vertex& v){ max_degree << MaxDegree(i, v.nadj); }); root = static_cast<MaxDegree>(max_degree).idx(); } else { root = choose_root(g); } // setup 'root' as the parent of itself delegate::call(g->vs+root, [=](G::Vertex& v){ v->parent = root; v->level = 0; }); // reset frontier queues next->clear(); frontier->clear(); // start with root as only thing in frontier delegate::call((g->vs+root).core(), [=]{ frontier->add(root); }); t = walltime(); bool top_down = true; int64_t prev_nf = -1; int64_t frontier_edges = 0; int64_t remaining_edges = g->nadj; while (!frontier->empty()) { auto nf = frontier->size(); VLOG(1) << "remaining_edges = " << remaining_edges << ", nf = " << nf << ", prev_nf = " << prev_nf << ", frontier_edges: " ; if (top_down && frontier_edges > remaining_edges/FLAGS_beamer_alpha && nf > prev_nf) { VLOG(1) << "switching to bottom-up"; top_down = false; } else if (!top_down && frontier_edges < g->nv/FLAGS_beamer_beta && nf < prev_nf) { VLOG(1) << "switching to top-down"; top_down = true; } edge_count = 0; if (top_down) { // iterate over vertices in this level of the frontier forall(frontier, [](VertexID& i){ // visit all the adjacencies of the vertex // note: this has to be 'async' to prevent deadlock from // running out of available workers forall<async>(adj(g,i), [i](G::Edge& e) { auto j = e.id; // at the core where the vertex is... delegate::call<async>(e.ga, [i,j](G::Vertex& vj){ // note: no synchronization needed because 'call' is // guaranteed to be executed atomically because it // does no blocking operations if (vj->parent == -1) { // claim parenthood vj->parent = i; vj->level = current_depth; next->add(j); edge_count += vj.nadj; } }); }); }); } else { // bottom-up forall<&phaser>(g, [](G::Vertex& v){ if (v->level != -1) return; auto va = make_linear(&v); forall<async,&phaser>(adj(g,v), [=,&v](G::Edge& e){ if (v->level != -1) return; phaser.enroll(); auto eva = e.ga; send_heap_message(eva.core(), [=]{ auto& ev = *eva.pointer(); if (ev->level != -1 && ev->level < current_depth) { auto eid = g->id(ev); send_heap_message(va.core(), [=]{ auto& v = *va.pointer(); if (v->level == -1) { next->add(g->id(v)); v->level = current_depth; v->parent = eid; edge_count += v.nadj; } phaser.complete(); }); } else { phaser.send_completion(va.core()); } }); }); }); } call_on_all_cores([=]{ current_depth++; // switch to next frontier level std::swap(frontier, next); }); next->clear(); frontier_edges = edge_count; remaining_edges -= frontier_edges; prev_nf = nf; } // while (frontier not empty) double this_bfs_time = walltime() - t; LOG(INFO) << "(root=" << root << ", time=" << this_bfs_time << ")"; if (!verified) { // only verify the first one to save time t = walltime(); bfs_nedge = verify(tg, g, root); verify_time = (walltime()-t); LOG(INFO) << verify_time; verified = true; Metrics::reset_all_cores(); // don't count the first one } else { total_time += this_bfs_time; } bfs_mteps += bfs_nedge / this_bfs_time / 1.0e6; } }