diff --git a/truss_decomposition/td_hls_v3/Makefile b/truss_decomposition/td_hls_v3/Makefile new file mode 100644 index 0000000..dd44771 --- /dev/null +++ b/truss_decomposition/td_hls_v3/Makefile @@ -0,0 +1,8 @@ +all: + g++ -std=c++11 truss_decomposition.cc truss_decomposition_host.cc -o td + +syn: + vivado_hls -f run_td_hls.tcl + +clean: + rm -rf td diff --git a/truss_decomposition/td_hls_v3/run_td_hls.tcl b/truss_decomposition/td_hls_v3/run_td_hls.tcl new file mode 100644 index 0000000..28451a3 --- /dev/null +++ b/truss_decomposition/td_hls_v3/run_td_hls.tcl @@ -0,0 +1,15 @@ +open_project -reset td_hls +set_top truss_decomposition +add_files truss_decomposition.cc +add_files -tb truss_decomposition_host.cc + +open_solution -reset "solution1" +set_part {xc7z020clg400-1} +create_clock -period 10 + +# csim_design + +csynth_design +export_design -format ip_catalog -version "0.002" + +exit diff --git a/truss_decomposition/td_hls_v3/truss_decomposition.cc b/truss_decomposition/td_hls_v3/truss_decomposition.cc new file mode 100644 index 0000000..6ead7f1 --- /dev/null +++ b/truss_decomposition/td_hls_v3/truss_decomposition.cc @@ -0,0 +1,144 @@ +#define HLS + +#ifndef HLS +#include "truss_decomposition.h" +#endif + +#include +#include +#include +#include + + +#define LOCAL_BUF_SIZE 8192 + +#ifndef HLS +int truss_decomposition(int *edge_tc, + int *triangles, + int *triangle_offsets, + int *progress, + int num_edges) +#else +int truss_decomposition(volatile int *edge_tc, + volatile int *triangles, + volatile int *triangle_offsets, + volatile int *progress, + int num_edges) +#endif +{ +#ifdef HLS +#pragma HLS INTERFACE m_axi port=edge_tc depth=32 offset=slave bundle=EDGE_TC +#pragma HLS INTERFACE m_axi port=triangles depth=32 offset=slave bundle=TRIANGLES +#pragma HLS INTERFACE m_axi port=triangle_offsets depth=32 offset=slave bundle=TRI_OFFSETS +#pragma HLS INTERFACE m_axi port=progress depth=32 offset=slave bundle=PROGRESS +#pragma HLS INTERFACE s_axilite register port=num_edges +#pragma HLS INTERFACE s_axilite register port=return +#endif + int num_edges_left = 0; + bool has_new_deletes = true; + int num_new_deletes = 0; + + int local_buf_1[LOCAL_BUF_SIZE]; + int local_buf_2[LOCAL_BUF_SIZE]; + int local_buf_3[LOCAL_BUF_SIZE]; + + int prev_buf_1 = 0; + int prev_buf_2 = 0; + int prev_buf_3 = 0; + + unsigned int k = 0; + while (1) + { + if (!has_new_deletes) + { + k++; + progress[0] = k; +#ifndef HLS + std::cout << "k = " << k << std::endl; +#endif + } + + num_edges_left = 0; + has_new_deletes = false; + num_new_deletes = 0; + + for (int i = 1; i <= num_edges; i++) // edge idx starts from 1 + { + int num_triangles = edge_tc[i]; + if ((num_triangles < k) && (num_triangles != 0)) + { + edge_tc[i] = 0; + has_new_deletes = true; + num_new_deletes++; + int triangle_list_start = triangle_offsets[i-1]; + int triangle_list_len = triangle_offsets[i] - triangle_list_start; + + if (i != prev_buf_1) + { + memcpy(local_buf_1, (const int*)&(triangles[triangle_list_start]), triangle_list_len*sizeof(int)); + prev_buf_1 = i; + } + + for (int triangle_idx = 0; triangle_idx < triangle_list_len; triangle_idx+=2) + { + int affected_edge_a = local_buf_1[triangle_idx]; + int affected_edge_b = local_buf_1[triangle_idx+1]; + if (affected_edge_a != 0) + { + int affected_edge_a_start = triangle_offsets[affected_edge_a-1]; + int affected_edge_b_start = triangle_offsets[affected_edge_b-1]; + int affected_edge_a_len = triangle_offsets[affected_edge_a] - affected_edge_a_start; + int affected_edge_b_len = triangle_offsets[affected_edge_b] - affected_edge_b_start; + + if (affected_edge_a != prev_buf_2) + { + memcpy(local_buf_2, (const int*)&(triangles[affected_edge_a_start]), affected_edge_a_len*sizeof(int)); + prev_buf_2 = affected_edge_a; + } + if (affected_edge_b != prev_buf_3) + { + memcpy(local_buf_3, (const int*)&(triangles[affected_edge_b_start]), affected_edge_b_len*sizeof(int)); + prev_buf_3 = affected_edge_b; + } + + for (int affected_idx = 0; affected_idx < affected_edge_a_len; affected_idx+=2) + { + int tmp_candidate_a = local_buf_2[affected_idx]; + int tmp_candidate_b = local_buf_2[affected_idx+1]; + if ((tmp_candidate_a == i) || (tmp_candidate_b == i)) + { + triangles[affected_edge_a_start+affected_idx] = 0; + triangles[affected_edge_a_start+affected_idx+1] = 0; + edge_tc[affected_edge_a]--; + break; + } + } + + for (int affected_idx = 0; affected_idx < affected_edge_b_len; affected_idx+=2) + { + int tmp_candidate_a = local_buf_3[affected_idx]; + int tmp_candidate_b = local_buf_3[affected_idx+1]; + if ((tmp_candidate_a == i) || (tmp_candidate_b == i)) + { + triangles[affected_edge_b_start+affected_idx] = 0; + triangles[affected_edge_b_start+affected_idx+1] = 0; + edge_tc[affected_edge_b]--; + break; + } + } + } + } + } + else + { + if (num_triangles != 0) + num_edges_left++; + } + } + + if (num_edges_left == 0) + break; + } + + return k+1; +} diff --git a/truss_decomposition/td_hls_v3/truss_decomposition.h b/truss_decomposition/td_hls_v3/truss_decomposition.h new file mode 100644 index 0000000..92bac9f --- /dev/null +++ b/truss_decomposition/td_hls_v3/truss_decomposition.h @@ -0,0 +1,42 @@ +#ifndef _TRUSS_DECOMPOSITION_H_ +#define _TRUSS_DECOMPOSITION_H_ + +/*#define HLS*/ + +#include +#include +#include +#include +#include +/*#include */ + +#include +#include +#include + +const unsigned int BUF_SIZE = 4096; +const unsigned int hash_key_bitwidth = 20; +const unsigned int hash_table_len = 1 << hash_key_bitwidth; +const unsigned int max_num_elems = 8; + + +void read_graph_td(const char *filename, + std::vector &edge_list, + std::vector &neighbor_list, + std::vector &offset_list); + +#ifndef HLS +int truss_decomposition(int *edge_tc, + int *triangles, + int *triangle_offsets, + int *progress, + int num_edges); +#else +int truss_decomposition(volatile int *edge_tc, + volatile int *triangles, + volatile int *triangle_offsets, + volatile int *progress, + int num_edges) +#endif + +#endif /* _TRUSS_DECOMPOSITION_H_ */ \ No newline at end of file diff --git a/truss_decomposition/td_hls_v3/truss_decomposition_host.cc b/truss_decomposition/td_hls_v3/truss_decomposition_host.cc new file mode 100644 index 0000000..e542bcc --- /dev/null +++ b/truss_decomposition/td_hls_v3/truss_decomposition_host.cc @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include +/*#include */ + +#include +#include + +#include "truss_decomposition.h" + +void read_graph_td(const char *filename, + std::vector &edge_list, + std::vector &neighbor_list, + std::vector &offset_list) +{ + std::ifstream ifs(filename); + + int degree_count = 0; + int prev_node = 0; + offset_list.push_back(0); + + if (ifs.is_open() && ifs.good()) + { + std::string str; + while (std::getline(ifs, str)) + { + if (!str.empty() && str[0] != '#') + { + std::istringstream ss(str); + int u, v; + ss >> u >> v; + if (prev_node != v) + { + offset_list.push_back(degree_count); + } + + prev_node = v; + if (u < v) + { + edge_list.push_back(v); + edge_list.push_back(u); + } + neighbor_list.push_back(u); + degree_count++; + } + } + } + ifs.close(); + offset_list.push_back(degree_count); +} + + +inline +int get_edge_idx(int node_a, int node_b, int* edge, int num_edges, int *hash_edge2idx) +{ +// std::cout << "TARGET: " << node_a << ", " << node_b << std::endl; + unsigned int ht_idx = (unsigned int)(((node_a & 0x3ff) << 10) + (node_b & 0x3ff)); + + bool edge_not_found = true; + for (unsigned int entry_idx = 0; entry_idx < max_num_elems; entry_idx++) + { + unsigned int ht_value = hash_edge2idx[ht_idx*max_num_elems+entry_idx]; + if (ht_value != 0) + { + if ((node_a == edge[ht_value-1]) && (node_b == edge[ht_value])) // edge found + return (ht_value+1)/2; + } + else + break; + } + if (edge_not_found) // search in the whole edge list; not likely to be true + { + // std::cout << "SLOW SEARCH IN DRAM!!!" << std::endl; + // std::cout << "=========================== SLOW: " << node_a << ", " << node_b << std::endl; + for (int k = 0; k < num_edges; k+=2) // TODO: use binary search + { + if ((node_a == edge[k]) && (node_b == edge[k+1])) + return k; + } + // std::cout << node_a << "->" << node_b << " DONE!!!" << std::endl; + } +} + +int init_triangle_counting(int neighbor[9], + int offset[7], + int edge[18], + int num_edges, + int edge_tc[9], + int *hash_edge2idx, + unsigned int *local_a, + unsigned int *local_b, + std::vector& triangle_list, + std::vector& triangle_list_offset + ) +{ + unsigned int i; + unsigned int node_a, node_b; + unsigned int offset_a, offset_b; + unsigned int len_a, len_b; + + unsigned int local_count = 0; + unsigned int global_count = 0; + + unsigned int idx_a = 0; + unsigned int idx_b = 0; + unsigned int prev_node_a = 0; + unsigned int prev_node_b = 0; + + unsigned int edge_node_p = 0; + unsigned int edge_node_q = 0; + + for (i = 0; i < num_edges; i+=2) + { +#pragma HLS pipeline + + triangle_list_offset.push_back(global_count*2); + + node_a = edge[i]; + node_b = edge[i+1]; + +/* if (node_a == 0 || node_b == 0) + continue;*/ + + if (node_a != prev_node_a) + { + offset_a = offset[node_a]; + len_a = offset[node_a + 1] - offset_a; + memcpy(local_a, (const unsigned int*)&(neighbor[offset_a]), len_a*sizeof(unsigned int)); + prev_node_a = node_a; + } + + if (node_b != prev_node_b) + { + offset_b = offset[node_b]; + len_b = offset[node_b + 1] - offset_b; + memcpy(local_b, (const unsigned int*)&(neighbor[offset_b]), len_b*sizeof(unsigned int)); + prev_node_b = node_b; + } + + idx_a = 0; + idx_b = 0; + + local_count = 0; + + while (idx_a < len_a && idx_b < len_b) + { +#pragma HLS pipeline + + edge_node_p = local_a[idx_a]; + edge_node_q = local_b[idx_b]; + + if (edge_node_p < edge_node_q) + idx_a++; + else if (edge_node_p > edge_node_q) + idx_b++; + else + { + int start_node, end_node; + start_node = (edge_node_p > node_a) ? edge_node_p : node_a; + end_node = (edge_node_p < node_a) ? edge_node_p : node_a; + triangle_list.push_back(get_edge_idx(start_node, end_node, edge, num_edges, hash_edge2idx)); + start_node = (edge_node_p > node_b) ? edge_node_p : node_b; + end_node = (edge_node_p < node_b) ? edge_node_p : node_b; + triangle_list.push_back(get_edge_idx(start_node, end_node, edge, num_edges, hash_edge2idx)); +// if ((edge_node_p != 0) && (edge_node_q != 0)) + local_count++; + idx_a++; + idx_b++; + } + } + global_count += local_count; + edge_tc[i/2+1] = local_count; + } + triangle_list_offset.push_back(global_count*2); +} + + +int main() +{ + std::vector edge_list, neighbor_list, offset_list, triangle_list, triangle_list_offset; + read_graph_td("/home/shuang91/vivado_projects/graph_challenge/graph/soc-Epinions1_adj.tsv", edge_list, neighbor_list, offset_list); + // read_graph_td("../graph/soc-Slashdot0811_adj.tsv", edge_list, neighbor_list, offset_list); + std::cout << "neighbor_list size= " << neighbor_list.size() << std::endl; + std::cout << "offset_list size= " << offset_list.size() << std::endl; + std::cout << "edge_list size= " << edge_list.size() << std::endl; + + unsigned int local_a[BUF_SIZE]; + unsigned int local_b[BUF_SIZE]; + + /* Construct hash table */ + std::cout << "hash_table_len = " << hash_table_len << std::endl; + + int *hash_edge2idx = (int *)malloc(max_num_elems*hash_table_len*sizeof(int)); + memset(hash_edge2idx, 0, max_num_elems*hash_table_len*sizeof(int)); + + for (int i = 0; i < edge_list.size(); i+=2) + { + unsigned int u = edge_list[i]; + unsigned int v = edge_list[i+1]; + unsigned int ht_idx = (unsigned int)(((u & 0x3ff) << 10) + (v & 0x3ff)); + assert(ht_idx < hash_table_len); + int entry_idx = 0; + while((hash_edge2idx[ht_idx*max_num_elems+entry_idx] != 0) && (entry_idx < max_num_elems)) entry_idx++; + if (entry_idx < max_num_elems) + hash_edge2idx[ht_idx*max_num_elems+entry_idx] = i+1; + else + { + std::cout << "spilling edge: " << u << ", " << v << std::endl; + } + } + + std::vector histogram; + histogram.resize(128); + for (int idx = 0; idx < histogram.size(); idx++) + histogram[idx] = 0; + + for (int i = 0; i < hash_table_len; i++) + { + int counter = 0; + for (int j = 0; j < max_num_elems; j++) + if (hash_edge2idx[i*max_num_elems+j] != 0) + counter++; + histogram[counter]++; + } + + for (int i = 0; i < 128; i++) + { + if (histogram[i] != 0) + std::cout << "size = " << i << ", num = " << histogram[i] << std::endl; + } + + int *edges = (int *)malloc( edge_list.size()*sizeof(int)); + int *neighbors = (int *)malloc(neighbor_list.size()*sizeof(int)); + int *offsets = (int *)malloc( offset_list.size()*sizeof(int)); + int *edge_tc = (int *)malloc((edge_list.size()/2+1)*sizeof(int)); + edge_tc[0] = 0; + + memcpy(edges , edge_list.data(), edge_list.size()*sizeof(int)); + memcpy(neighbors, neighbor_list.data(), neighbor_list.size()*sizeof(int)); + memcpy(offsets , offset_list.data(), offset_list.size()*sizeof(int)); + + init_triangle_counting(neighbors, offsets, edges, edge_list.size(), edge_tc, hash_edge2idx, local_a, local_b, triangle_list, triangle_list_offset); + + long long int count_check = 0; + int max_num_triangles = 0; + for (int i = 0; i <= edge_list.size()/2; i++) + { +// std::cout << edge_tc[i] << " "; + count_check += edge_tc[i]; + if (edge_tc[i] > max_num_triangles) + max_num_triangles = edge_tc[i]; + } + + std::cout << "num of triangles = " << count_check/3 << std::endl; + std::cout << "max num of triangles of an edge = " << max_num_triangles << std::endl; + std::cout << "size of triangle_list = " << triangle_list.size() << std::endl; + std::cout << "size of triangle_list / 6 = " << triangle_list.size() / 6 << std::endl; + std::cout << "size of triangle_list_offset = " << triangle_list_offset.size() << std::endl; + + int *triangles = (int *)malloc(triangle_list.size()*sizeof(int)); + int *triangle_offsets = (int *)malloc(triangle_list_offset.size()*sizeof(int)); + memcpy(triangles, triangle_list.data(), triangle_list.size()*sizeof(int)); + memcpy(triangle_offsets, triangle_list_offset.data(), triangle_list_offset.size()*sizeof(int)); + + delete [] edges; + delete [] neighbors; + delete [] offsets; + + int num_edges = edge_list.size()/2; + + int progress[6]; + +// return 0; + + int result = truss_decomposition(edge_tc, triangles, triangle_offsets, progress, num_edges); + printf("result = %d\n", result); + return 0; +} diff --git a/truss_decomposition/td_v3/Makefile b/truss_decomposition/td_host_v3/Makefile similarity index 100% rename from truss_decomposition/td_v3/Makefile rename to truss_decomposition/td_host_v3/Makefile diff --git a/truss_decomposition/td_v3/libsds_lib.so b/truss_decomposition/td_host_v3/libsds_lib.so similarity index 100% rename from truss_decomposition/td_v3/libsds_lib.so rename to truss_decomposition/td_host_v3/libsds_lib.so diff --git a/truss_decomposition/td_v3/libxlnk_cma.h b/truss_decomposition/td_host_v3/libxlnk_cma.h similarity index 100% rename from truss_decomposition/td_v3/libxlnk_cma.h rename to truss_decomposition/td_host_v3/libxlnk_cma.h diff --git a/truss_decomposition/td_v3/td b/truss_decomposition/td_host_v3/td similarity index 100% rename from truss_decomposition/td_v3/td rename to truss_decomposition/td_host_v3/td diff --git a/truss_decomposition/td_v3/td.cpp b/truss_decomposition/td_host_v3/td.cpp similarity index 100% rename from truss_decomposition/td_v3/td.cpp rename to truss_decomposition/td_host_v3/td.cpp diff --git a/truss_decomposition/td_v3/td_backup0712.cpp b/truss_decomposition/td_host_v3/td_backup0712.cpp similarity index 100% rename from truss_decomposition/td_v3/td_backup0712.cpp rename to truss_decomposition/td_host_v3/td_backup0712.cpp diff --git a/truss_decomposition/td_v3/td_v2.1.bit b/truss_decomposition/td_host_v3/td_v2.1.bit similarity index 100% rename from truss_decomposition/td_v3/td_v2.1.bit rename to truss_decomposition/td_host_v3/td_v2.1.bit diff --git a/truss_decomposition/td_v3/td_v2.1.tcl b/truss_decomposition/td_host_v3/td_v2.1.tcl similarity index 100% rename from truss_decomposition/td_v3/td_v2.1.tcl rename to truss_decomposition/td_host_v3/td_v2.1.tcl diff --git a/truss_decomposition/td_v3/td_v2.2.bit b/truss_decomposition/td_host_v3/td_v2.2.bit similarity index 100% rename from truss_decomposition/td_v3/td_v2.2.bit rename to truss_decomposition/td_host_v3/td_v2.2.bit diff --git a/truss_decomposition/td_v3/td_v2.2.tcl b/truss_decomposition/td_host_v3/td_v2.2.tcl similarity index 100% rename from truss_decomposition/td_v3/td_v2.2.tcl rename to truss_decomposition/td_host_v3/td_v2.2.tcl diff --git a/truss_decomposition/td_v3/td_v2.3.bit b/truss_decomposition/td_host_v3/td_v2.3.bit similarity index 100% rename from truss_decomposition/td_v3/td_v2.3.bit rename to truss_decomposition/td_host_v3/td_v2.3.bit diff --git a/truss_decomposition/td_v3/td_v2.3.tcl b/truss_decomposition/td_host_v3/td_v2.3.tcl similarity index 100% rename from truss_decomposition/td_v3/td_v2.3.tcl rename to truss_decomposition/td_host_v3/td_v2.3.tcl diff --git a/truss_decomposition/td_v3/td_v2.4.bit b/truss_decomposition/td_host_v3/td_v2.4.bit similarity index 100% rename from truss_decomposition/td_v3/td_v2.4.bit rename to truss_decomposition/td_host_v3/td_v2.4.bit diff --git a/truss_decomposition/td_v3/td_v2.4.tcl b/truss_decomposition/td_host_v3/td_v2.4.tcl similarity index 100% rename from truss_decomposition/td_v3/td_v2.4.tcl rename to truss_decomposition/td_host_v3/td_v2.4.tcl diff --git a/truss_decomposition/td_v3/td_v2.bit b/truss_decomposition/td_host_v3/td_v2.bit similarity index 100% rename from truss_decomposition/td_v3/td_v2.bit rename to truss_decomposition/td_host_v3/td_v2.bit diff --git a/truss_decomposition/td_v3/td_v2.tcl b/truss_decomposition/td_host_v3/td_v2.tcl similarity index 100% rename from truss_decomposition/td_v3/td_v2.tcl rename to truss_decomposition/td_host_v3/td_v2.tcl