diff --git a/benchmarks/concurrentKNN/octTree/compile.sh b/benchmarks/concurrentKNN/octTree/compile.sh index 919ae141..e0e9e948 100755 --- a/benchmarks/concurrentKNN/octTree/compile.sh +++ b/benchmarks/concurrentKNN/octTree/compile.sh @@ -2,6 +2,7 @@ set -o xtrace +##NORMAL BENCH # lock-based g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DNoHelp -DVersioned -DHWStamp -include neighbors_bench.h -o neighbors_bench ../bench/neighborsTime.C -DHOMEGROWN -pthread -ldl -L/usr/local/lib -ljemalloc @@ -17,6 +18,7 @@ g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DVersioned -DLazyS # lock-free, path copying g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DVersioned -DLazyStamp -DPathCopy -include neighbors_bench.h -o neighbors_bench_path_copy_lockfree ../bench/neighborsTime.C -DHOMEGROWN -pthread -ldl -L/usr/local/lib -ljemalloc +##WORKING SET BENCH # lock-based g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DNoHelp -DVersioned -DHWStamp -include working_set_bench.h -o working_set_bench ../bench/neighborsTime.C -DHOMEGROWN -pthread -ldl -L/usr/local/lib -ljemalloc @@ -25,3 +27,6 @@ g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DNoHelp -DVersione # lock-based, path copying g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DNoHelp -DVersioned -DPathCopy -DHWStamp -include working_set_bench.h -o working_set_bench_path_copy ../bench/neighborsTime.C -DHOMEGROWN -pthread -ldl -L/usr/local/lib -ljemalloc + +# lock-free +g++ -DHOMEGROWN -pthread -mcx16 -O3 -std=c++17 -DNDEBUG -I . -DVersioned -DLazyStamp -include working_set_bench.h -o working_set_bench_lockfree ../bench/neighborsTime.C -DHOMEGROWN -pthread -ldl -L/usr/local/lib -ljemalloc diff --git a/benchmarks/concurrentKNN/octTree/create_graphs.py b/benchmarks/concurrentKNN/octTree/create_graphs.py index 2ed391cd..9350e021 100644 --- a/benchmarks/concurrentKNN/octTree/create_graphs.py +++ b/benchmarks/concurrentKNN/octTree/create_graphs.py @@ -28,6 +28,8 @@ def __init__(self, color, marker, linestyle, name, binary, ds_type): 'neighbors_bench_hoh-10' : DSInfo("C6", mk[6], "-", "CLEANN-Tree-HOH, k=10", "blah", "blah"), 'working_set_bench-1' : DSInfo("C0", mk[0], "-", "CLEANN-Tree, k=1", "blah", "blah"), 'working_set_bench-10' : DSInfo("C1", mk[1], "-", "CLEANN-Tree, k=10", "blah", "blah"), + 'working_set_bench_lockfree-1' : DSInfo("C7", mk[7], "-", "CLEANN-Tree-LF, k=1", "blah", "blah"), + 'working_set_bench_lockfree-10' : DSInfo("C8", mk[8], "-", "CLEANN-Tree-LF, k=10", "blah", "blah"), 'working_set_bench_hoh-1' : DSInfo("C5", mk[5], "-", "CLEANN-Tree-HOH, k=1", "blah", "blah"), 'working_set_bench_hoh-10' : DSInfo("C6", mk[6], "-", "CLEANN-Tree-HOH, k=10", "blah", "blah"), 'working_set_bench_path_copy-1' : DSInfo("C3", mk[3], "-", "CLEANN-Tree-PC, k=1", "blah", "blah"), @@ -36,6 +38,8 @@ def __init__(self, color, marker, linestyle, name, binary, ds_type): 'neighbors_bench_path_copy-10' : DSInfo("C4", mk[4], "-", "CLEANN-Tree-PC, k=10", "blah", "blah"), 'neighbors_bench_lockfree-1' : DSInfo("C7", mk[7], "-", "CLEANN-Tree-LF, k=1", "blah", "blah"), 'neighbors_bench_lockfree-10' : DSInfo("C8", mk[8], "-", "CLEANN-Tree-LF, k=10", "blah", "blah"), + 'neighbors_bench_path_copy_lockfree-1' : DSInfo("C2", mk[2], "-", "CLEANN-Tree-PC, k=1", "blah", "blah"), + 'neighbors_bench_path_copy_lockfree-10' : DSInfo("C9", mk[9], "-", "CLEANN-Tree-PC, k=10", "blah", "blah"), 'range_bench-.014' : DSInfo("C0", mk[0], "-", "CLEANN-Tree, r=5", "blah", "blah"), 'range_bench-.0176' : DSInfo("C1", mk[1], "-", "CLEANN-Tree, r=10", "blah", "blah"), 'range_bench_path_copy-.014' : DSInfo("C3", mk[3], "-", "CLEANN-Tree-PC, r=5", "blah", "blah"), @@ -48,13 +52,6 @@ def __init__(self, color, marker, linestyle, name, binary, ds_type): def toString(algname, th, ratio, size): return algname + '-' + str(th) + 'u-' + str(ratio) + "s-" + str(size) -# def export_legend(legend, filename="legend.pdf", expand=[-5,-5,5,5]): -# fig = legend.figure -# fig.canvas.draw() -# bbox = legend.get_window_extent() -# bbox = bbox.from_extents(*(bbox.extents + np.array(expand))) -# bbox = bbox.transformed(fig.dpi_scale_trans.inverted()) -# fig.savefig(filename, dpi="figure", bbox_inches=bbox) def export_legend(legend, filename="legend.pdf"): fig = legend.figure @@ -305,6 +302,10 @@ def plot_size_graph(throughput, stddev, thread, ratios, maxkeys, algs, graph_nam plt.title(graphtitle) plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y)) plt.savefig(outputFile, bbox_inches='tight') + + if paper_ver: + legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=8, framealpha=0.0) + export_legend(legend, 'graphs/' + graph_name + '_legend.pdf') plt.close('all') def plot_size_graphs(throughput, stddev, threads, ratios, maxkeys, algs, graph_name, paper_ver=False): @@ -393,6 +394,10 @@ def plot_ratio_graph(throughput, stddev, thread, ratios, size, algs, graph_name, plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y)) plt.savefig(outputFile, bbox_inches='tight') + + if paper_ver: + legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=8, framealpha=0.0) + export_legend(legend, 'graphs/' + graph_name + '_legend.pdf') plt.close('all') def plot_ratio_graphs(throughput, stddev, threads, ratios, size, algs, graph_name, paper_ver=False): @@ -476,17 +481,9 @@ def plot_scalability_graph(throughput, stddev, threads, ratio, size, algs, graph plt.savefig(outputFile, bbox_inches='tight') if paper_ver: - if graph_name == 'lists': - legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=2, framealpha=0.0) - elif graph_name == 'sets': - legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=3, framealpha=0.0) - else: - legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=8, framealpha=0.0) - # outputFile = 'graphs/' + graph_name + '_legend.pdf' - # legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=7, framealpha=0.0) + legend = plt.legend(loc='center left', bbox_to_anchor=(legend_x, legend_y), ncol=8, framealpha=0.0) export_legend(legend, 'graphs/' + graph_name + '_legend.pdf') - # plt.close('all') - # return + plt.close('all') diff --git a/benchmarks/concurrentKNN/octTree/experiments.sh b/benchmarks/concurrentKNN/octTree/experiments.sh index 5c1986c2..c7df405d 100644 --- a/benchmarks/concurrentKNN/octTree/experiments.sh +++ b/benchmarks/concurrentKNN/octTree/experiments.sh @@ -1,29 +1,38 @@ #!/bin/bash mkdir -p graphs #run to quickly test the setup -python3 run_experiments.py [working_set_bench,working_set_bench_hoh] [36,72,144] [50] [1] 3 [3DinCube_WorkingSet_11M] +# python3 run_experiments.py [neighbors_bench] [36,72,144] [50] [1,10] 3 [3DinCube_20M] +# python3 run_experiments.py [working_set_bench,working_set_bench_hoh,working_set_bench_path_copy] [1,2,8,12,36,72,144] [50] [1] 3 [3DinCube_WorkingSet_11M] # python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy,neighbors_bench_lockfree,neighbors_bench_hoh] [1,2,4,8,12,36,72,144] [100] [1] 3 [3DinCube_20M] -# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,4,8,12,36,72,144] [50] [1,10] 3 3DinCube_20M -# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,4,8,12,36,72,144] [10] [1,10] 3 3DinCube_20M +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,8,12,36,72,144] [100] [1,10] 3 [3DinCube_20M] +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,8,12,36,72,144] [50] [1,10] 3 3DinCube_20M +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,8,12,36,72,144] [10] [1,10] 3 3DinCube_20M # python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,4,8,12,36,72,144] [50] [1,10] 2 [2DinCube_20M] -# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [144] [50] [1,10] 3 [3DinCube_2M,3DinCube_20M,3DinCube_200M,3DinCube_2B] -# python3 run_experiments.py [neighbors_bench] [144] [0,25,50,75,100] [1] 3 [3Dplummer_20M] -# python3 run_experiments.py [neighbors_bench] [144] [0,25,50,75,100] [1] 3 [3DinCube_20M] -# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,4,8,12,36,72,144] [10] [1,10] 3 3DPlummer_20M +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [144] [0,25,50,75,100] [1] 3 [3Dplummer_20M] +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [144] [0,25,50,75,100] [1] 3 [3DinCube_20M] -# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,4,8,12,36,72,144] [50] [1,10] 3 lucy3D_14M +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,8,12,36,72,144] [10] [1,10] 3 [3Dplummer_20M] -# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,4,8,12,36,72,144] [50] [1,10] 3 thai_statue5M +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,8,12,36,72,144] [50] [1,10] 3 [lucy3D_14M] -# python3 run_experiments.py [range_bench,range_bench_path_copy] [1,2,4,8,12,36,72,144] [10] [.014,.0176] 3 [3Dplummer_20M] +# python3 run_experiments.py [neighbors_bench,neighbors_bench_path_copy] [1,2,8,12,36,72,144] [50] [1,10] 3 [thai_statue5M] + +# python3 run_experiments.py [range_bench,range_bench_path_copy] [1,2,8,12,36,72,144] [10] [.014,.0176] 3 [3Dplummer_20M] + +# python3 run_experiments.py [neighbors_bench] [144] [50] [1] 3 [3DinCube_2M,3DinCube_20M,3DinCube_200M,3DinCube_2B] + +##OVERSUBSCRIPTION + +# python3 run_experiments.py [neighbors_bench,neighbors_bench_lockfree,neighbors_bench_path_copy,neighbors_bench_path_copy_lockfree] [144,196,288,432,500] [50] [1] 3 [3DinCube_20M] +python3 run_experiments.py [working_set_bench,working_set_bench_lockfree] [144,196,288,432,500] [50] [1] 3 [3DinCube_WorkingSet_11M] diff --git a/benchmarks/concurrentKNN/octTree/k_nearest_neighbors.h b/benchmarks/concurrentKNN/octTree/k_nearest_neighbors.h index 5b23b2eb..054a6940 100644 --- a/benchmarks/concurrentKNN/octTree/k_nearest_neighbors.h +++ b/benchmarks/concurrentKNN/octTree/k_nearest_neighbors.h @@ -651,10 +651,12 @@ node* find_leaf(node* T){ //takes in a point since interleave_bits() takes in a for(indexed_point p : T->Indexed_Pts()) { if(points_equal(p.second->pt, q.second->pt)) return false; } - - auto points = parlay::tabulate(T->size()+1, [&] (long i) { - return (i == T->size()) ? q : T->Indexed_Pts()[i]; - }, 1000); + std::vector points; + for(auto i : T->Indexed_Pts()) points.push_back(i); + points.push_back(q); + // auto points = parlay::tabulate(T->size()+1, [&] (long i) { + // return (i == T->size()) ? q : T->Indexed_Pts()[i]; + // }, 1000); //two cases: either (1) the leaf size is below the cutoff, in which case //we create a new leaf with the point q added, or (2) the leaf needs to be //split into an internal node and two leaf children @@ -684,9 +686,12 @@ node* find_leaf(node* T){ //takes in a point since interleave_bits() takes in a cut_point = parlay::internal::binary_search(points, less); new_bit--; } - parlay::slice pts = parlay::make_slice(points); - auto left_s = parlay::tabulate(cut_point, [&] (size_t i) {return points[i];}, 1000); - auto right_s = parlay::tabulate(points.size()-cut_point, [&] (size_t i) {return points[cut_point+i];}, 1000); + std::vector left_s; + std::vector right_s; + for(size_t i=0; i points = {q}; - node* R = node::new_leaf(parlay::make_slice(std::move(points)), cur_bit-1); + node* R = node::new_leaf(std::move(points), cur_bit-1); //new parent node should replace T as G's child node* P; if(lookup_bit(q.first, cur_bit) == 0) P = node::new_node(R, T, cur_bit); @@ -784,8 +789,8 @@ node* find_leaf(node* T){ //takes in a point since interleave_bits() takes in a //we know we are in case 1 //form leaf node* G = parent; - parlay::sequence points = {q}; - node* R = node::new_leaf(parlay::make_slice(points), cur_bit-1); + std::vector points = {q}; + node* R = node::new_leaf(points, cur_bit-1); //new parent node should replace T as G's child node* P; if(lookup_bit(q.first, cur_bit) == 0) P = node::new_node(R, T, cur_bit); @@ -860,8 +865,9 @@ node* find_leaf(node* T){ //takes in a point since interleave_bits() takes in a } } - auto points = parlay::tabulate(T->size()+1, [&] (long i) { - return (i == T->size()) ? q : T->Indexed_Pts()[i];}, 1000); + std::vector points; + for(auto i : T->Indexed_Pts()) points.push_back(i); + points.push_back(q); node* G = parent; bool left; if(G != nullptr) left = (G->Left() == T); @@ -900,9 +906,12 @@ node* find_leaf(node* T){ //takes in a point since interleave_bits() takes in a cut_point = parlay::internal::binary_search(points, less); new_bit--; } - parlay::slice pts = parlay::make_slice(points); - auto left_s = parlay::tabulate(cut_point, [&] (size_t i) {return points[i];}, 1000); - auto right_s = parlay::tabulate(points.size()-cut_point, [&] (size_t i) {return points[cut_point+i];}, 1000); + std::vector left_s; + std::vector right_s; + for(size_t i=0; i &path){ - parlay::sequence pts; + std::vector pts; bool cont = false; bool q_present = false; for(indexed_point p : T->Indexed_Pts()){ @@ -1223,7 +1232,7 @@ node* find_leaf(node* T){ //takes in a point since interleave_bits() takes in a } pair delete_from_leaf(indexed_point q, node* parent, node* grandparent, node* T){ - parlay::sequence pts; + std::vector pts; bool cont = false; bool q_present = false; for(indexed_point p : T->Indexed_Pts()){ diff --git a/benchmarks/concurrentKNN/octTree/oct_tree.h b/benchmarks/concurrentKNN/octTree/oct_tree.h index e72d6add..f488659e 100644 --- a/benchmarks/concurrentKNN/octTree/oct_tree.h +++ b/benchmarks/concurrentKNN/octTree/oct_tree.h @@ -80,7 +80,8 @@ struct oct_tree { // generates a box consisting of a lower left corner, // and an upper right corner. - static box get_box(parlay::sequence &V) { // parlay::sequence &V) { + template + static box get_box(Seq &V) { // parlay::sequence &V) { size_t n = V.size(); // std::cout << n << std::endl; auto minmax = [&] (box x, box y) { @@ -111,7 +112,7 @@ struct oct_tree { return (L.load() == nullptr) && (R.load() == nullptr);} node* Left() {return L.load();} node* Right() {return R.load();} - parlay::sequence& Indexed_Pts(){return indexed_pts;} + std::vector& Indexed_Pts(){return indexed_pts;} // leaf_seq& Vertices() {return P;} void set_size(size_t s){n=s;} @@ -131,7 +132,7 @@ struct oct_tree { } // construct a leaf node with a sequence of points directly in it - node(parlay::sequence &Pts, int currentBit) : removed(false), n(Pts.size()) { + node(std::vector &Pts, int currentBit) : removed(false), n(Pts.size()) { // strips off the integer tag, no longer needed indexed_pts = std::move(Pts); L = R = nullptr; @@ -141,7 +142,7 @@ struct oct_tree { } // construct a leaf node with a sequence of points directly in it - node(parlay::sequence &Pts, int currentBit, box &B) : removed(false), n(Pts.size()) { + node(std::vector &Pts, int currentBit, box &B) : removed(false), n(Pts.size()) { // strips off the integer tag, no longer needed indexed_pts = std::move(Pts); L = R = nullptr; @@ -150,39 +151,6 @@ struct oct_tree { bit = currentBit; } - // construct a leaf node with a sequence of points directly in it - node(slice_t Pts, int currentBit, box &B) : removed(false), n(Pts.size()) { - // strips off the integer tag, no longer needed - indexed_pts = parlay::sequence(n); - for (int i = 0; i < n; i++) { - indexed_pts[i] = Pts[i]; - } - L = R = nullptr; - b = B; - set_center(); - bit = currentBit; - } - - - // construct a leaf node with a sequence of points directly in it - node(slice_t Pts, int currentBit) : removed(false), n(Pts.size()) { - // strips off the integer tag, no longer needed - indexed_pts = parlay::sequence(n); - for (int i = 0; i < n; i++) { - if(indexed_pts.size() < n) { - std::stringstream ss; - ss << "n = " << n << std::endl << "P.size() = " << indexed_pts.size() << std::endl; - std::cout << ss.str() << std::endl; - exit(1); - } - indexed_pts[i] = Pts[i]; - } - L = R = nullptr; - b = get_box(indexed_pts); - set_center(); - bit = currentBit; - } - // construct an internal binary node node(node* L, node* R, int currentBit) : removed(false), L(L), R(R) { b = box(L->b.first.minCoords(R->b.first), @@ -209,52 +177,30 @@ struct oct_tree { } } - static node* new_leaf(slice_t Pts, int currentBit) { - node* r = alloc_node(Pts, currentBit); - assert(Pts.begin() != nullptr); - // new (r) node(); - return r; - } - static node* new_leaf(slice_t Pts, int currentBit, box B) { - node* r = alloc_node(Pts, currentBit, B); - assert(Pts.begin() != nullptr); - // new (r) node(); - return r; - } - static node* new_leaf(parlay::sequence Pts, int currentBit) { + static node* new_leaf(std::vector Pts, int currentBit) { node* r = alloc_node(Pts, currentBit); assert(Pts.begin() != nullptr); - // new (r) node(); return r; } - static node* new_leaf(parlay::sequence Pts, int currentBit, box B) { + static node* new_leaf(std::vector Pts, int currentBit, box B) { node* r = alloc_node(Pts, currentBit, B); assert(Pts.begin() != nullptr); - // new (r) node(); return r; } static node* new_node(node* L, node* R, int currentBit) { node* nd = alloc_node(L, R, currentBit); - // new (nd) node(); return nd; } static node* new_node(node* L, node* R, int currentBit, box B) { node* nd = alloc_node(L, R, currentBit, B); - // new (nd) node(); return nd; } - // ~node() { - // // need to collect in parallel - // parlay::par_do_if(n > 1000, - // [&] () { delete_tree(L.load());}, - // [&] () { delete_tree(R.load());}); - // } parlay::sequence flatten() { parlay::sequence r(n); @@ -322,7 +268,7 @@ struct oct_tree { verlib::versioned_ptr R; box b; point centerv; - parlay::sequence indexed_pts; + std::vector indexed_pts; // leaf_seq P; void set_center() { @@ -430,7 +376,9 @@ struct oct_tree { // if run out of bit, or small then generate a leaf if (bit == 0 || n < node_cutoff) { - return node::new_leaf(Pts, bit); + std::vector points; + for(auto i : Pts) points.push_back(i); + return node::new_leaf(points, bit); } else { // this was extracted to lookup_bit but left as is here since the less function requires mask and val diff --git a/benchmarks/concurrentKNN/octTree/run_experiments.py b/benchmarks/concurrentKNN/octTree/run_experiments.py index 3eac86b8..31ba95fb 100644 --- a/benchmarks/concurrentKNN/octTree/run_experiments.py +++ b/benchmarks/concurrentKNN/octTree/run_experiments.py @@ -12,9 +12,11 @@ ds_options = { "neighbors_bench" : "neighbors_bench", "neighbors_bench_path_copy" : "neighbors_bench_path_copy", + "neighbors_bench_path_copy_lockfree" : "neighbors_bench_path_copy_lockfree", "neighbors_bench_lockfree" : "neighbors_bench_lockfree", "neighbors_bench_hoh" : "neighbors_bench_hoh", "working_set_bench" : "working_set_bench", + "working_set_bench_lockfree" : "working_set_bench_lockfree", "working_set_bench_hoh" : "working_set_bench_hoh", "working_set_bench_path_copy" : "working_set_bench_path_copy", "range_bench" : "../../rangeQueryKDTree/range/range_bench", @@ -24,9 +26,11 @@ ds_keys = { "neighbors_bench" : "neighbors_bench", "neighbors_bench_path_copy" : "neighbors_bench_path_copy", + "neighbors_bench_path_copy_lockfree" : "neighbors_bench_path_copy_lockfree", "neighbors_bench_lockfree" : "neighbors_bench_lockfree", "neighbors_bench_hoh" : "neighbors_bench_hoh", "working_set_bench" : "working_set_bench", + "working_set_bench_lockfree" : "working_set_bench_lockfree", "working_set_bench_hoh" : "working_set_bench_hoh", "working_set_bench_path_copy" : "working_set_bench_path_copy", "../../rangeQueryKDTree/range/range_bench" : "range_bench", @@ -222,10 +226,11 @@ def runtest(test,procs,u,k,d,infile,extra,outfile) : for k in query_sizes: alg_names.append(ds+"-"+str(k)) - +args.paper_ver = True if(len(input_names) <= 1): plot_scalability_graphs(throughput, stddev, threads, ratios, sizes[0], alg_names, "scalability_"+graph_name, args.paper_ver) plot_ratio_graphs(throughput, stddev, threads, ratios, sizes[0], alg_names, "ratio_"+graph_name, args.paper_ver) else: plot_size_graphs(throughput, stddev, threads, ratios, sizes, alg_names, "sizes_"+graph_name, args.paper_ver) +