void test_loop_decomposition_global() { BOOST_MESSAGE("Testing loop_decomposition_public..."); VLOG(1) << "loop_decomposition_public"; int N = 160000; my_gce.enroll(); impl::loop_decomposition<unbound,&my_gce>(0, N, [](int64_t start, int64_t iters) { if ( start%10000==0 ) { VLOG(1) << "loop(" << start << ", " << iters << ")"; } }); my_gce.complete(); my_gce.wait(); }
void try_global_ce() { BOOST_MESSAGE("GlobalCompletionEvent:"); const int64_t N = 128; int64_t x = 0; auto xa = make_global(&x); BOOST_MESSAGE(" block on user_main only"); // gce.reset_all(); (don't need to call `reset` anymore) on_all_cores([xa]{ Core origin = mycore(); gce.enroll(N+1); for (int i=0; i<N; i++) { spawn<unbound>([xa,origin]{ delegate::fetch_and_add(xa, 1); complete(make_global(&gce,origin)); }); } gce.complete(); }); gce.wait(); BOOST_CHECK_EQUAL(x, N*cores()); BOOST_MESSAGE(" block in SPMD tasks"); x = 0; // gce.reset_all(); (don't need this anymore) on_all_cores([xa,N]{ int y = 0; auto ya = make_global(&y); Core origin = mycore(); gce.enroll(N); for (int i=0; i<N; i++) { spawn<unbound>([xa,ya,origin]{ delegate::fetch_and_add(xa, 1); delegate::fetch_and_add(ya, 1); complete(make_global(&gce,origin)); }); } gce.wait(); BOOST_CHECK_EQUAL(y, N); }); BOOST_CHECK_EQUAL(x, N*cores()); }
void try_global_ce_recursive() { BOOST_MESSAGE("GlobalCompletionEvent (recursive spawns):"); const int64_t N = 128; int64_t x = 0; auto xa = make_global(&x); BOOST_MESSAGE(" block on user_main only"); // gce.reset_all(); on_all_cores([xa]{ gce.enroll(); Core origin = mycore(); for (int i=0; i<N; i++) { gce.enroll(); spawn<unbound>([xa,origin]{ delegate::fetch_and_add(xa, 1); complete(make_global(&gce,origin)); }); } gce.complete(); }); // overload Core0 with extra work rec_spawn(xa, N*2); gce.wait(); BOOST_CHECK_EQUAL(x, N*cores()+N*2); BOOST_MESSAGE(" block in SPMD tasks"); x = 0; // gce.reset_all(); on_all_cores([xa,N]{ int y = 0; auto ya = make_global(&y); Core origin = mycore(); gce.enroll(N); for (int i=0; i<N; i++) { spawn<unbound>([xa,ya,origin]{ delegate::fetch_and_add(xa, 1); delegate::fetch_and_add(ya, 1); complete(make_global(&gce,origin)); }); } if (mycore() == 0) { // overload Core0 with extra work rec_spawn(xa, N*2); } gce.wait(); BOOST_CHECK_EQUAL(y, N); }); BOOST_CHECK_EQUAL(x, N*cores()+N*2); BOOST_MESSAGE("test finish block syntactic sugar"); long xx = 0; auto a = make_global(&xx); finish([=]{ forall<unbound,async>(0, N, [=](int64_t i){ delegate::increment<async>(a, 1); }); }); BOOST_CHECK_EQUAL(xx, N); }
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; } }