From a5ab648ad813524b31855e16701beb5853820867 Mon Sep 17 00:00:00 2001 From: Yida Date: Fri, 13 Dec 2024 23:35:52 +0800 Subject: [PATCH] v4.2.0 --- PanguLU_Users_s_Guide.pdf | Bin 0 -> 215457 bytes README.md | 34 +- examples/mmio_highlevel.h | 1 + examples/run.sh | 4 +- make.inc | 14 +- src/languages/pangulu_en.h | 62 + src/pangulu.c | 65 +- src/pangulu_common.h | 127 +- src/pangulu_destroy.c | 10 +- src/pangulu_gessm_fp64_cuda.c | 4 +- src/pangulu_kernel_interface.c | 15 +- src/pangulu_malloc.c | 101 +- src/pangulu_numeric.c | 2 +- src/pangulu_preprocessing.c | 717 +++------- src/pangulu_reorder.c | 275 ++-- src/pangulu_symbolic.c | 5 + src/pangulu_time.c | 2 +- src/pangulu_tstrf_fp64.c | 8 +- src/pangulu_tstrf_fp64_cuda.c | 8 +- src/pangulu_utils.c | 1160 ++++++++++++++++- .../02_GPU/01_CUDA/000_CUDA/pangulu_cuda.cu | 4 +- .../02_GPU/01_CUDA/000_CUDA/pangulu_cuda.h | 4 +- 22 files changed, 1801 insertions(+), 821 deletions(-) create mode 100644 PanguLU_Users_s_Guide.pdf create mode 100644 src/languages/pangulu_en.h diff --git a/PanguLU_Users_s_Guide.pdf b/PanguLU_Users_s_Guide.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f58e5fdbd5ef19a6017475f0195cc55800eb801a GIT binary patch literal 215457 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%0AnErSAkvHdl8 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 SWv8No*||{Py%SfEK>a^v>Df8} literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 2064778..367d4e0 100644 --- a/README.md +++ b/README.md @@ -154,32 +154,36 @@ In this example, 6 processes are used to test, the block_size is 4, matrix name ## Release versions -####

Version 4.1.0 (Sep. 01, 2024)

+####

Version 4.2.0 (Dec. 13, 2024)

-* Optimized memory usage of numeric factorisation and solving. +* Updated preprocessing phase to distributed data structure. + +####

Version 4.1.0 (Sep. 1, 2024)

+ +* Optimized memory usage of numeric factorisation and solving; * Added parallel building support. ####

Version 4.0.0 (Jul. 24, 2024)

-* Optimized user interfaces of solver routines. -* Optimized performance of numeric factorisation phase on CPU platforms. -* Added support on complex matrix solving. -* Optimized pre-processing performance. +* Optimized user interfaces of solver routines; +* Optimized performamce of numeric factorisation phase on CPU platform; +* Added support on complex matrix solving; +* Optimized preprocessing performance; ####

Version 3.5.0 (Aug. 06, 2023)

* Updated the pre-processing phase with OpenMP. -* Updated the compilation method, compilling libpangulu.so and libpangulu.a at the same time. -* Updated timing for the reordering phase, the symbolic factorisation phase, and the pre-processing phase. -* Computed GFLOPS for the numeric factorisation phase. +* Updated the compilation method of PanguLU, compile libpangulu.so and libpangulu.a at the same time. +* Updated timing for the reorder phase, the symbolic factorisation phase, the pre-processing phase. +* Added GFLOPS for the numeric factorisation phase. ####

Version 3.0.0 (Apr. 02, 2023)

-* Used an adaptive method for selecting sparse BLAS in the numeric factorisation phase. -* Added the reordering phase. -* Added the symbolic factorisation phase. -* Added the MC64 algorithm in the reordering phase. -* Added an interface for 64-bit METIS package in the reordering phase. +* Used adaptive selection sparse BLAS in the numeric factorisation phase. +* Added the reorder phase. +* Added the symbolic factorisation phase. +* Added mc64 sorting algorithm in the reorder phase. +* Added interface for 64-bit metis package in the reorder phase. ####

Version 2.0.0 (Jul.  22, 2022)

@@ -191,7 +195,7 @@ In this example, 6 processes are used to test, the block_size is 4, matrix name ####

Version 1.0.0 (Oct. 19, 2021)

* Used a rule-based 2D LU factorisation scheduling strategy. -* Used sparse BLAS for floating point calculations on GPUs. +* Used Sparse BLAS for floating point calculations on GPUs. * Added the pre-processing phase. * Added the numeric factorisation phase. * Added the triangular solve phase. diff --git a/examples/mmio_highlevel.h b/examples/mmio_highlevel.h index 841a414..6fdee49 100644 --- a/examples/mmio_highlevel.h +++ b/examples/mmio_highlevel.h @@ -136,6 +136,7 @@ int mmio_info(sparse_index_t *m, sparse_index_t *n, sparse_pointer_t *nnz, spars // free tmp space free(csr_colIdx_tmp); free(csr_rowIdx_tmp); + free(csr_row_ptr_counter); return 0; } diff --git a/examples/run.sh b/examples/run.sh index 8d55958..817e439 100755 --- a/examples/run.sh +++ b/examples/run.sh @@ -7,6 +7,6 @@ if [ ! -f $1 ];then exit fi -echo mpirun -np $[$NP] ./$numeric_file -nb $nb -f $Smatrix_name +echo mpirun -np $NP ./$numeric_file -nb $nb -f $Smatrix_name -mpirun -np $[$NP] ./$numeric_file -nb $nb -f $Smatrix_name +mpirun -np $NP ./$numeric_file -nb $nb -f $Smatrix_name diff --git a/make.inc b/make.inc index 98ef885..0fcaa3a 100644 --- a/make.inc +++ b/make.inc @@ -1,18 +1,18 @@ COMPILE_LEVEL = -O3 #0201000,GPU_CUDA -CUDA_PATH = /path/to/cuda +CUDA_PATH = /usr/local/cuda CUDA_INC = -I$(CUDA_PATH)/include CUDA_LIB = -L$(CUDA_PATH)/lib64 -lcudart -lcusparse NVCC = nvcc $(COMPILE_LEVEL) NVCCFLAGS = $(PANGULU_FLAGS) -w -Xptxas -dlcm=cg -gencode=arch=compute_61,code=sm_61 -gencode=arch=compute_61,code=compute_61 $(CUDA_INC) $(CUDA_LIB) #general -CC = gcc $(COMPILE_LEVEL) -MPICC = mpicc $(COMPILE_LEVEL) -OPENBLAS_INC = -I/path/to/OpenBLAS/include -OPENBLAS_LIB = -L/path/to/OpenBLAS/lib -lopenblas +CC = gcc $(COMPILE_LEVEL) #-fsanitize=address +MPICC = mpicc $(COMPILE_LEVEL) #-fsanitize=address +OPENBLAS_INC = -I$(PATH_TO_OPENBLAS_INC) +OPENBLAS_LIB = -L$(PATH_TO_OPENBLAS_LIB) -lopenblas MPICCFLAGS = $(OPENBLAS_INC) $(CUDA_INC) $(OPENBLAS_LIB) -fopenmp -lpthread -lm MPICCLINK = $(OPENBLAS_LIB) -METISFLAGS = -I/path/to/GKlib/include -I/path/to/METIS/include -PANGULU_FLAGS = -DPANGULU_LOG_INFO -DCALCULATE_TYPE_R64 -DPANGULU_MC64 -DMETIS #-DGPU_OPEN -DHT_IS_OPEN +METISFLAGS = -I$(PATH_TO_GKLIB_INC) -I$(PATH_TO_METIS_I64_INC) +PANGULU_FLAGS = -DPANGULU_LOG_INFO -DCALCULATE_TYPE_R64 -DMETIS -DPANGULU_MC64 #-DGPU_OPEN -DHT_IS_OPEN diff --git a/src/languages/pangulu_en.h b/src/languages/pangulu_en.h new file mode 100644 index 0000000..46b7bb7 --- /dev/null +++ b/src/languages/pangulu_en.h @@ -0,0 +1,62 @@ +#ifdef PANGULU_EN + +#ifdef PANGULU_LOG_ERROR +#define PANGULU_E_NB_IS_ZERO "[PanguLU Error] nb is zero.\n" +#define PANGULU_E_INVALID_HEAP_SELECT "[PanguLU Error] Invalid heap comparing strategy.\n" +#define PANGULU_E_HEAP_FULL "[PanguLU Error] The heap is full on rank " FMT_PANGULU_INT32_T ".\n", rank +#define PANGULU_E_HEAP_EMPTY "[PanguLU Error] The heap is empty on rank " FMT_PANGULU_INT32_T ".\n", rank +#define PANGULU_E_CPU_MEM "[PanguLU Error] Failed to allocate " FMT_PANGULU_INT64_T " byte(s). CPU memory is not enough. %s:" FMT_PANGULU_INT64_T "\n", size, file, line +#define PANGULU_E_ISEND_CSR "[PanguLU Error] pangulu_isend_whole_pangulu_smatrix_csr error. value != s->value.\n" +#define PANGULU_E_ISEND_CSC "[PanguLU Error] pangulu_isend_whole_pangulu_smatrix_csc error. value != s->value_csc.\n" +#define PANGULU_E_ROW_IS_NULL "[PanguLU Error] The matrix has zero row(s).\n" +#define PANGULU_E_ROW_DONT_HAVE_DIA "[PanguLU Error] Row[" FMT_PANGULU_EXBLOCK_IDX "] don't have diagonal element.\n", i +#define PANGULU_E_ERR_IN_RRCL "[PanguLU Error] Invalid numeric factorization task on rank " FMT_PANGULU_INT32_T ". row=" FMT_PANGULU_INT64_T " col=" FMT_PANGULU_INT64_T " level=" FMT_PANGULU_INT64_T "\n", rank, row, col, level +#define PANGULU_E_K_ID "[PanguLU Error] Invalid kernel id " FMT_PANGULU_INT64_T " for numeric factorization.\n", kernel_id +#define PANGULU_E_ASYM "[PanguLU Error] MPI_Barrier_asym error.\n" +#define PANGULU_E_ADD_DIA "[PanguLU Error] pangulu_add_diagonal_element error\n" +#define PANGULU_E_CUDA_MALLOC "[PanguLU Error] Failed to cudaMalloc %lu byte(s). GPU memory is not enough.\n", size +#define PANGULU_E_ROW_IS_ZERO "[PanguLU Error] Invalid input matrix.\n" +#define PANGULU_E_MAX_NULL "[PanguLU Error] pangulu_mc64 internal error. (now_row_max==0)\n" +#define PANGULU_E_WORK_ERR "[PanguLU Error] Invalid kernel id " FMT_PANGULU_INT64_T " for sptrsv.\n", kernel_id +#define PANGULU_E_BIP_PTR_INVALID "[PanguLU Error] Invalid pangulu_block_info pointer.\n" +#define PANGULU_E_BIP_INVALID "[PanguLU Error] Invalid pangulu_block_info.\n" +#define PANGULU_E_BIP_NOT_EMPTY "[PanguLU Error] Block info pool is not empty.\n" +#define PANGULU_E_BIP_OUT_OF_RANGE "[PanguLU Error] PANGULU_BIP index out of range.\n" +#define PANGULU_E_OPTION_IS_NULLPTR "[PanguLU Error] Option struct pointer is NULL. (pangulu_init)\n" +#define PANGULU_E_GSTRF_OPTION_IS_NULLPTR "[PanguLU Error] Option struct pointer is NULL. (pangulu_gstrf)\n" +#define PANGULU_E_GSTRS_OPTION_IS_NULLPTR "[PanguLU Error] Option struct pointer is NULL. (pangulu_gstrs)\n" +#endif // PANGULU_LOG_ERROR + +#ifdef PANGULU_LOG_WARNING +#define PANGULU_W_RANK_HEAP_DONT_NULL "[PanguLU Warning] " FMT_PANGULU_INT64_T " task remaining on rank " FMT_PANGULU_INT32_T ".\n", heap->length, rank +#define PANGULU_W_ERR_RANK "[PanguLU Warning] Receiving message error on rank " FMT_PANGULU_INT32_T ".\n", rank +#define PANGULU_W_BIP_INCREASE_SPEED_TOO_SMALL "[PanguLU Warning] PANGULU_BIP_INCREASE_SPEED too small.\n" +#define PANGULU_W_GPU_BIG_BLOCK "[PanguLU Warning] When GPU is open, init_options->nb > 256 and pangulu_inblock_idx isn't pangulu_uint32_t, performance will be limited.\n" +#define PANGULU_W_COMPLEX_FALLBACK "[PanguLU Warning] Calculating complex value on GPU is not supported. Fallback to CPU.\n" +#endif // PANGULU_LOG_WARNING + +#ifdef PANGULU_LOG_INFO +#define PANGULU_I_VECT2NORM_ERR "[PanguLU Info] || Ax - B || / || Ax || = %12.4le.\n", error +#define PANGULU_I_CHECK_PASS "[PanguLU Info] Check ------------------------------------- pass\n" +#define PANGULU_I_CHECK_ERROR "[PanguLU Info] Check ------------------------------------ error\n" +#define PANGULU_I_DEV_IS "[PanguLU Info] Device is %s.\n", prop.name +#define PANGULU_I_TASK_INFO "[PanguLU Info] Info of inserting task is: row=" FMT_PANGULU_INT64_T " col=" FMT_PANGULU_INT64_T " level=" FMT_PANGULU_INT64_T " kernel=" FMT_PANGULU_INT64_T ".\n", row, col, task_level, kernel_id +#define PANGULU_I_HEAP_LEN "[PanguLU Info] heap.length=" FMT_PANGULU_INT64_T " heap.capacity=" FMT_PANGULU_INT64_T "\n", heap->length, heap->max_length +#define PANGULU_I_ADAPTIVE_KERNEL_SELECTION_ON "[PanguLU Info] ADAPTIVE_KERNEL_SELECTION ------------- ON\n" +#define PANGULU_I_ADAPTIVE_KERNEL_SELECTION_OFF "[PanguLU Info] ADAPTIVE_KERNEL_SELECTION ------------- OFF\n" +#define PANGULU_I_SYNCHRONIZE_FREE_ON "[PanguLU Info] SYNCHRONIZE_FREE ---------------------- ON\n" +#define PANGULU_I_SYNCHRONIZE_FREE_OFF "[PanguLU Info] SYNCHRONIZE_FREE ---------------------- OFF\n" +#ifdef METIS +#define PANGULU_I_BASIC_INFO "[PanguLU Info] n=" FMT_PANGULU_INT64_T " nnz=" FMT_PANGULU_EXBLOCK_PTR " nb=" FMT_PANGULU_INT32_T " mpi_process=" FMT_PANGULU_INT32_T " preprocessing_thread=%d METIS:%s\n", n, origin_smatrix->rowpointer[n], nb, size, init_options->nthread, (sizeof(idx_t) == 4) ? ("i32") : ((sizeof(idx_t) == 8) ? ("i64") : ("?")) +#else +#define PANGULU_I_BASIC_INFO "[PanguLU Info] n=" FMT_PANGULU_INT64_T " nnz=" FMT_PANGULU_EXBLOCK_PTR " nb=" FMT_PANGULU_INT32_T " mpi_process=" FMT_PANGULU_INT32_T " preprocessing_thread=%d\n", n, origin_smatrix->rowpointer[n], nb, size, init_options->nthread +#endif +#define PANGULU_I_TIME_REORDER "[PanguLU Info] Reordering time is %lf s.\n", elapsed_time +#define PANGULU_I_TIME_SYMBOLIC "[PanguLU Info] Symbolic factorization time is %lf s.\n", elapsed_time +#define PANGULU_I_TIME_PRE "[PanguLU Info] Preprocessing time is %lf s.\n", elapsed_time +#define PANGULU_I_TIME_NUMERICAL "[PanguLU Info] Numeric factorization time is %lf s.\n", elapsed_time //, flop / pangulu_get_spend_time(common) / 1000000000.0 +#define PANGULU_I_TIME_SPTRSV "[PanguLU Info] Solving time is %lf s.\n", elapsed_time +#define PANGULU_I_SYMBOLIC_NONZERO "[PanguLU Info] Symbolic nonzero count is " FMT_PANGULU_EXBLOCK_PTR ".\n",*symbolic_nnz +#endif // PANGULU_LOG_INFO + +#endif // #ifdef PANGULU_EN \ No newline at end of file diff --git a/src/pangulu.c b/src/pangulu.c index 82a054f..2b76b9e 100644 --- a/src/pangulu.c +++ b/src/pangulu.c @@ -17,7 +17,7 @@ pangulu_int64_t INDEX_NUM = 0; pangulu_int32_t pangu_omp_num_threads = 1; pangulu_int64_t flop = 0; -double time_transport = 0.0; +double time_transpose = 0.0; double time_isend = 0.0; double time_receive = 0.0; double time_getrf = 0.0; @@ -46,6 +46,9 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz { MPI_Comm_rank(MPI_COMM_WORLD, &rank); + struct timeval time_start; + double elapsed_time; + pangulu_int32_t size; MPI_Comm_size(MPI_COMM_WORLD, &size); pangulu_common *common = (pangulu_common *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_common)); @@ -111,7 +114,6 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz pangulu_int32_t q = common->q; pangulu_int32_t nb = common->nb; MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_start(common); common->n = pangulu_bcast_n(origin_smatrix->row, 0); pangulu_int64_t n = common->n; omp_set_num_threads(init_options->nthread); @@ -120,16 +122,16 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz #endif if (rank == 0) { -#ifdef ADAPTIVE_KERNEL_SELECTION - printf(PANGULU_I_ADAPTIVE_KERNEL_SELECTION_ON); -#else - printf(PANGULU_I_ADAPTIVE_KERNEL_SELECTION_OFF); -#endif -#ifdef SYNCHRONIZE_FREE - printf(PANGULU_I_SYNCHRONIZE_FREE_ON); -#else - printf(PANGULU_I_SYNCHRONIZE_FREE_OFF); -#endif +// #ifdef ADAPTIVE_KERNEL_SELECTION +// printf(PANGULU_I_ADAPTIVE_KERNEL_SELECTION_ON); +// #else +// printf(PANGULU_I_ADAPTIVE_KERNEL_SELECTION_OFF); +// #endif +// #ifdef SYNCHRONIZE_FREE +// printf(PANGULU_I_SYNCHRONIZE_FREE_ON); +// #else +// printf(PANGULU_I_SYNCHRONIZE_FREE_OFF); +// #endif #ifdef PANGULU_GPU_COMPLEX_FALLBACK_FLAG printf(PANGULU_W_COMPLEX_FALLBACK); #endif @@ -168,14 +170,14 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz block_common->rank_col_length = (block_common->block_length / q + (((block_common->block_length % q) > (rank % q)) ? 1 : 0)); block_common->every_level_length = PANGULU_MIN(block_common->every_level_length, block_common->block_length); MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_start(common); + pangulu_time_start(&time_start); pangulu_reorder(block_smatrix, origin_smatrix, reorder_matrix); MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_stop(common); + elapsed_time = pangulu_time_stop(&time_start); if (rank == 0) { printf(PANGULU_I_TIME_REORDER); @@ -184,8 +186,7 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz calculate_time = 0; MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_start(common); - + pangulu_time_start(&time_start); if (rank == 0) { pangulu_symbolic(block_common, @@ -194,7 +195,7 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz } MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_stop(common); + elapsed_time = pangulu_time_stop(&time_start); if (rank == 0) { printf(PANGULU_I_TIME_SYMBOLIC); @@ -203,30 +204,26 @@ void pangulu_init(pangulu_exblock_idx pangulu_n, pangulu_exblock_ptr pangulu_nnz pangulu_init_heap_select(0); MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_start(common); - + pangulu_time_start(&time_start); pangulu_preprocessing( block_common, block_smatrix, reorder_matrix, init_options->nthread); -#ifdef PANGULU_SPTRSV - -#endif MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_stop(common); + elapsed_time = pangulu_time_stop(&time_start); if (rank == 0) { printf(PANGULU_I_TIME_PRE); } - pangulu_free(__FILE__, __LINE__, block_smatrix->symbolic_rowpointer); - block_smatrix->symbolic_rowpointer = NULL; + // pangulu_free(__FILE__, __LINE__, block_smatrix->symbolic_rowpointer); + // block_smatrix->symbolic_rowpointer = NULL; - pangulu_free(__FILE__, __LINE__, block_smatrix->symbolic_columnindex); - block_smatrix->symbolic_columnindex = NULL; + // pangulu_free(__FILE__, __LINE__, block_smatrix->symbolic_columnindex); + // block_smatrix->symbolic_columnindex = NULL; pangulu_free(__FILE__, __LINE__, origin_smatrix); origin_smatrix = NULL; @@ -249,6 +246,9 @@ void pangulu_gstrf(pangulu_gstrf_options *gstrf_options, void **pangulu_handle) pangulu_block_smatrix *block_smatrix = (*(pangulu_handle_t **)pangulu_handle)->block_smatrix; pangulu_common *common = (*(pangulu_handle_t **)pangulu_handle)->commmon; + struct timeval time_start; + double elapsed_time; + if (rank == 0) { if (gstrf_options == NULL) @@ -270,13 +270,13 @@ void pangulu_gstrf(pangulu_gstrf_options *gstrf_options, void **pangulu_handle) pangulu_time_init(); MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_start(common); + pangulu_time_start(&time_start); pangulu_numeric(block_common, block_smatrix); MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_stop(common); + elapsed_time = pangulu_time_stop(&time_start); if (rank == 0) { @@ -306,6 +306,9 @@ void pangulu_gstrs(calculate_type *rhs, pangulu_gstrs_options *gstrs_options, vo pangulu_block_smatrix *block_smatrix = (*(pangulu_handle_t **)pangulu_handle)->block_smatrix; pangulu_common *common = (*(pangulu_handle_t **)pangulu_handle)->commmon; + struct timeval time_start; + double elapsed_time; + if (rank == 0) { if (gstrs_options == NULL) @@ -340,14 +343,14 @@ void pangulu_gstrs(calculate_type *rhs, pangulu_gstrs_options *gstrs_options, vo #ifdef PANGULU_SPTRSV MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_start(common); + pangulu_time_start(&time_start); pangulu_sptrsv_L(block_common, block_smatrix); pangulu_init_heap_select(4); pangulu_sptrsv_U(block_common, block_smatrix); MPI_Barrier(MPI_COMM_WORLD); - pangulu_time_stop(common); + elapsed_time = pangulu_time_stop(&time_start); if (rank == 0) { diff --git a/src/pangulu_common.h b/src/pangulu_common.h index 796fc7e..dbd7157 100644 --- a/src/pangulu_common.h +++ b/src/pangulu_common.h @@ -101,7 +101,7 @@ extern pangulu_int64_t cpu_peak_memory; extern pangulu_int64_t gpu_memory; extern pangulu_int64_t flop; -extern double time_transport; +extern double time_transpose; extern double time_isend; extern double time_receive; extern double time_getrf; @@ -174,8 +174,8 @@ typedef int idx_t; #include "./platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.h" #endif -// #if !defined(PANGULU_EN_US) -#define PANGULU_EN_US +// #if !defined(PANGULU_EN) +#define PANGULU_EN // #endif #if defined(PANGULU_LOG_INFO) && !defined(PANGULU_LOG_WARNING) @@ -185,7 +185,7 @@ typedef int idx_t; #define PANGULU_LOG_ERROR #endif -#include "./languages/pangulu_en_us.h" +#include "./languages/pangulu_en.h" #if !defined(PANGULU_LOG_ERROR) #define PANGULU_E_NB_IS_ZERO "" @@ -251,6 +251,7 @@ typedef int idx_t; #define PANGULU_BIP_SIBLING_LEN 8 #define PANGULU_BIP_MAP_LENGTH(index_upper_bound) ((index_upper_bound + PANGULU_BIP_SIBLING_LEN - 1) / PANGULU_BIP_SIBLING_LEN) +#define PANGULU_ICEIL(a, b) (((a) + (b) - 1) / (b)) #define setbit(x, y) x |= (1 << y) // set the yth bit of x is 1 #define getbit(x, y) ((x) >> (y) & 1) // get the yth bit of x @@ -476,7 +477,6 @@ typedef struct pangulu_block_smatrix pangulu_inblock_ptr *block_smatrix_nnza_num; pangulu_inblock_ptr *block_smatrix_non_zero_vector_l; pangulu_inblock_ptr *block_smatrix_non_zero_vector_u; - char *blocks_current_rank; pangulu_smatrix *big_pangulu_smatrix_value; pangulu_inblock_ptr *l_pangulu_smatrix_columnpointer; pangulu_inblock_idx *l_pangulu_smatrix_rowindex; @@ -1020,8 +1020,6 @@ void pangulu_mc64(pangulu_origin_smatrix *s, pangulu_exblock_idx **perm, pangulu calculate_type **row_scale, calculate_type **col_scale); #endif -void pangulu_origin_smatrix_transport_transport_iperm(pangulu_origin_smatrix *s, pangulu_origin_smatrix *new_S, pangulu_exblock_idx *metis_perm); - #ifdef METIS void pangulu_get_graph_struct(pangulu_origin_smatrix *s, idx_t **xadj_adress, idx_t **adjincy_adress); @@ -1414,9 +1412,13 @@ void pangulu_init_pangulu_origin_smatrix(pangulu_origin_smatrix *s); void pangulu_read_pangulu_origin_smatrix(pangulu_origin_smatrix *s, int wcs_n, long long wcs_nnz, pangulu_exblock_ptr *csr_rowptr, pangulu_exblock_idx *csr_colidx, calculate_type *csr_value); -void pangulu_time_start(pangulu_common *common); +// void pangulu_time_start(pangulu_common *common); + +// void pangulu_time_stop(pangulu_common *common); -void pangulu_time_stop(pangulu_common *common); +void pangulu_time_start(struct timeval* start); + +double pangulu_time_stop(struct timeval* start); void pangulu_memcpy_zero_pangulu_smatrix_csc_value(pangulu_smatrix *s); @@ -1426,9 +1428,9 @@ void pangulu_display_pangulu_smatrix_csc(pangulu_smatrix *s); double pangulu_get_spend_time(pangulu_common *common); -void pangulu_transport_pangulu_smatrix_csc_to_csr(pangulu_smatrix *s); +void pangulu_transpose_pangulu_smatrix_csc_to_csr(pangulu_smatrix *s); -void pangulu_transport_pangulu_smatrix_csr_to_csc(pangulu_smatrix *s); +void pangulu_transpose_pangulu_smatrix_csr_to_csc(pangulu_smatrix *s); void pangulu_pangulu_smatrix_memcpy_rowpointer_csr(pangulu_smatrix *s, pangulu_smatrix *copy_S); @@ -1551,5 +1553,108 @@ const pangulu_block_info *pangulu_bip_get(pangulu_int64_t index, pangulu_block_i pangulu_block_info *pangulu_bip_set(pangulu_int64_t index, pangulu_block_info_pool *BIP); +void pangulu_convert_csr_to_csc( + int free_csrmatrix, + pangulu_exblock_idx n, + pangulu_exblock_ptr** csr_pointer, + pangulu_exblock_idx** csr_index, + calculate_type** csr_value, + pangulu_exblock_ptr** csc_pointer, + pangulu_exblock_idx** csc_index, + calculate_type** csc_value +); + +void pangulu_cm_distribute_csc_to_distcsc( + pangulu_int32_t root_rank, + int rootproc_free_originmatrix, + pangulu_exblock_idx* n, + pangulu_inblock_idx rowchunk_align, + pangulu_int32_t* distcsc_nproc, + pangulu_exblock_idx* n_loc, + + pangulu_exblock_ptr** distcsc_proc_nnzptr, + pangulu_exblock_ptr** distcsc_pointer, + pangulu_exblock_idx** distcsc_index, + calculate_type** distcsc_value +); + +void pangulu_cm_distribute_distcsc_to_distbcsc( + int rootproc_free_originmatrix, + int malloc_distbcsc_value, + pangulu_exblock_idx n_glo, + pangulu_exblock_idx n_loc, + pangulu_inblock_idx block_order, + + pangulu_exblock_ptr* distcsc_proc_nnzptr, + pangulu_exblock_ptr* distcsc_pointer, + pangulu_exblock_idx* distcsc_index, + calculate_type* distcsc_value, + + pangulu_exblock_ptr** bcsc_struct_pointer, + pangulu_exblock_idx** bcsc_struct_index, + pangulu_exblock_ptr** bcsc_struct_nnzptr, + pangulu_inblock_ptr*** bcsc_inblock_pointers, + pangulu_inblock_idx*** bcsc_inblock_indeces, + calculate_type*** bcsc_values +); + +void pangulu_convert_ordered_halfsymcsc_to_csc_struct( + int free_halfmatrix, + int if_colsort, + pangulu_exblock_idx n, + pangulu_exblock_ptr** half_csc_pointer, + pangulu_exblock_idx** half_csc_index, + pangulu_exblock_ptr** csc_pointer, + pangulu_exblock_idx** csc_index +); + +void pangulu_convert_bcsc_fill_value_to_struct( + int free_valuebcsc, + pangulu_exblock_idx n, + pangulu_inblock_idx nb, + + pangulu_exblock_ptr* value_bcsc_struct_pointer, + pangulu_exblock_idx* value_bcsc_struct_index, + pangulu_exblock_ptr* value_bcsc_struct_nnzptr, + pangulu_inblock_ptr** value_bcsc_inblock_pointers, + pangulu_inblock_idx** value_bcsc_inblock_indeces, + calculate_type** value_bcsc_values, + + pangulu_exblock_ptr* struct_bcsc_struct_pointer, + pangulu_exblock_idx* struct_bcsc_struct_index, + pangulu_exblock_ptr* struct_bcsc_struct_nnzptr, + pangulu_inblock_ptr** struct_bcsc_inblock_pointers, + pangulu_inblock_idx** struct_bcsc_inblock_indeces, + calculate_type** struct_bcsc_values +); + +void pangulu_cm_rank(pangulu_int32_t* rank); + +void pangulu_cm_size(pangulu_int32_t* size); + +void pangulu_cm_sync(); + +void pangulu_cm_bcast(void *buffer, int count, MPI_Datatype datatype, int root); + +void pangulu_cm_isend(char* buf, pangulu_int64_t count, pangulu_int32_t remote_rank, pangulu_int32_t tag, pangulu_int32_t tag_ub); + +void pangulu_cm_send(char* buf, pangulu_int64_t count, pangulu_int32_t remote_rank, pangulu_int32_t tag, pangulu_int32_t tag_ub); + +void pangulu_cm_recv(char* buf, pangulu_int64_t count, pangulu_int32_t fetch_rank, pangulu_int32_t tag, pangulu_int32_t tag_ub); + +void pangulu_sort_exblock_struct( + pangulu_exblock_idx n, + pangulu_exblock_ptr* pointer, + pangulu_exblock_idx* index, + pangulu_int32_t nthread +); + +int cmp_exidx_asc(const void* a, const void* b); + +void pangulu_kvsort(pangulu_exblock_idx *key, calculate_type *val, pangulu_int64_t start, pangulu_int64_t end); + + +void pangulu_cm_sync_asym(int wake_rank); + #endif // PANGULU_PLATFORM_ENV #endif // PANGULU_COMMON_H \ No newline at end of file diff --git a/src/pangulu_destroy.c b/src/pangulu_destroy.c index 0045564..54c9479 100644 --- a/src/pangulu_destroy.c +++ b/src/pangulu_destroy.c @@ -220,10 +220,16 @@ void pangulu_destroy(pangulu_block_common *block_common, pangulu_block_info_pool* BIP = block_smatrix->BIP; for(pangulu_exblock_ptr i=0;icurrent_rank_block_count;i++){ - pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].columnpointer); pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].csc_to_csr_index); pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].bin_rowpointer); pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].bin_rowindex); + pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].rowpointer); + pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].columnindex); + pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[i].value); + } + + if(block_smatrix->current_rank_block_count){ + pangulu_free(__FILE__, __LINE__, block_smatrix->big_pangulu_smatrix_value[0].columnpointer); } for(pangulu_exblock_ptr i=0;irank_col_length;i++){ @@ -257,7 +263,7 @@ void pangulu_destroy(pangulu_block_common *block_common, #endif } } - pangulu_free(__FILE__, __LINE__, block_smatrix->blocks_current_rank); + // pangulu_free(__FILE__, __LINE__, block_smatrix->blocks_current_rank); for (pangulu_int64_t i = 0; i < L_smatrix_nzz * every_level_length; i++) { diff --git a/src/pangulu_gessm_fp64_cuda.c b/src/pangulu_gessm_fp64_cuda.c index 8883f5c..7459f4e 100644 --- a/src/pangulu_gessm_fp64_cuda.c +++ b/src/pangulu_gessm_fp64_cuda.c @@ -191,13 +191,13 @@ void pangulu_gessm_interface_g_v2(pangulu_smatrix *a, pangulu_smatrix *x) { pangulu_smatrix_cuda_memcpy_value_csc(a, a); - pangulu_transport_pangulu_smatrix_csc_to_csr(a); + pangulu_transpose_pangulu_smatrix_csc_to_csr(a); pangulu_smatrix_cuda_memcpy_complete_csr(a, a); pangulu_gessm_fp64_cuda_v8(a, l, x); pangulu_smatrix_cuda_memcpy_value_csr(a, x); - pangulu_transport_pangulu_smatrix_csr_to_csc(a); + pangulu_transpose_pangulu_smatrix_csr_to_csc(a); } void pangulu_gessm_interface_g_v3(pangulu_smatrix *a, pangulu_smatrix *l, diff --git a/src/pangulu_kernel_interface.c b/src/pangulu_kernel_interface.c index 3512725..7e16dc8 100644 --- a/src/pangulu_kernel_interface.c +++ b/src/pangulu_kernel_interface.c @@ -45,6 +45,7 @@ void pangulu_getrf_interface(pangulu_smatrix *a, pangulu_smatrix *l, pangulu_sma #endif // ADD_GPU_MEMORY #else // GPU_OPEN + pangulu_getrf_fp64(a, l, u); #endif // GPU_OPEN @@ -135,10 +136,10 @@ void pangulu_tstrf_interface(pangulu_smatrix *a, pangulu_smatrix *save_X, pangul pangulu_pangulu_smatrix_memcpy_columnpointer_csc(save_X, a); // // csr - // pangulu_transport_pangulu_smatrix_csc_to_csr(a); + // pangulu_transpose_pangulu_smatrix_csc_to_csr(a); // pangulu_pangulu_smatrix_memcpy_value_csc_copy_length(calculate_X, a); // pangulu_tstrf_fp64_CPU_6(a, calculate_X, u); - // pangulu_transport_pangulu_smatrix_csr_to_csc(a); + // pangulu_transpose_pangulu_smatrix_csr_to_csc(a); // pangulu_pangulu_smatrix_memcpy_columnpointer_csc(save_X, a); #endif // GPU_OPEN @@ -166,11 +167,11 @@ void pangulu_gessm_interface(pangulu_smatrix *a, pangulu_smatrix *save_X, pangul #ifndef CPU_OPTION pangulu_smatrix_cuda_memcpy_value_csc(a, a); - pangulu_transport_pangulu_smatrix_csc_to_csr(a); + pangulu_transpose_pangulu_smatrix_csc_to_csr(a); pangulu_pangulu_smatrix_memcpy_value_csr_copy_length(calculate_X, a); - pangulu_transport_pangulu_smatrix_csc_to_csr(l); + pangulu_transpose_pangulu_smatrix_csc_to_csr(l); pangulu_gessm_interface_cpu(a, l, calculate_X); - pangulu_transport_pangulu_smatrix_csr_to_csc(a); + pangulu_transpose_pangulu_smatrix_csr_to_csc(a); #else /*******************Choose the best performance(性能择优)*************************/ @@ -229,10 +230,10 @@ void pangulu_gessm_interface(pangulu_smatrix *a, pangulu_smatrix *save_X, pangul pangulu_pangulu_smatrix_memcpy_value_csr_copy_length(calculate_X, a); pangulu_gessm_fp64_cpu_6(a, l, calculate_X); pangulu_pangulu_smatrix_memcpy_columnpointer_csc(save_X, a); - // pangulu_transport_pangulu_smatrix_csc_to_csr(a); + // pangulu_transpose_pangulu_smatrix_csc_to_csr(a); // pangulu_pangulu_smatrix_memcpy_value_csr_copy_length(calculate_X, a); // pangulu_gessm_interface_CPU_csr(a, l, calculate_X); - // pangulu_transport_pangulu_smatrix_csr_to_csc(a); + // pangulu_transpose_pangulu_smatrix_csr_to_csc(a); // pangulu_pangulu_smatrix_memcpy_columnpointer_csc(save_X, a); #endif diff --git a/src/pangulu_malloc.c b/src/pangulu_malloc.c index 74591d4..4c79893 100644 --- a/src/pangulu_malloc.c +++ b/src/pangulu_malloc.c @@ -2,6 +2,9 @@ void *pangulu_malloc(const char* file, pangulu_int64_t line, pangulu_int64_t size) { + if(size == 0){ + return NULL; + } cpu_memory += size; if (cpu_memory > cpu_peak_memory) { @@ -20,6 +23,10 @@ void *pangulu_malloc(const char* file, pangulu_int64_t line, pangulu_int64_t siz void *pangulu_realloc(const char* file, pangulu_int64_t line, void* oldptr, pangulu_int64_t size) { + if(size == 0){ + pangulu_free(__FILE__, __LINE__, oldptr); + return NULL; + } cpu_memory += size; if (cpu_memory > cpu_peak_memory) { @@ -189,7 +196,7 @@ void pangulu_get_pangulu_smatrix_to_l(pangulu_smatrix *s, void pangulu_smatrix_add_more_memory(pangulu_smatrix *a) { - // add CPU moemory + // add CPU memory pangulu_int64_t nnzA = a->rowpointer[a->row]; pangulu_int64_t n = a->row; char *now_malloc_space = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_ptr) * (n + 1) + sizeof(pangulu_inblock_idx) * nnzA + sizeof(calculate_type) * nnzA); @@ -274,7 +281,7 @@ void pangulu_smatrix_add_more_memory(pangulu_smatrix *a) void pangulu_smatrix_add_more_memory_csr(pangulu_smatrix *a) { - // add CPU moemory + // add CPU memory pangulu_int64_t nnzA = a->nnz; pangulu_int64_t n = a->row; @@ -360,7 +367,7 @@ void pangulu_smatrix_add_more_memory_csr(pangulu_smatrix *a) void pangulu_smatrix_add_csc(pangulu_smatrix *a) { - // add csc moemory + // add csc memory pangulu_int64_t nnzA = a->rowpointer[a->row]; pangulu_int64_t n = a->row; char *now_malloc_space = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_ptr) * (n + 1) + sizeof(pangulu_inblock_idx) * nnzA + sizeof(calculate_type) * nnzA); @@ -411,57 +418,105 @@ void pangulu_smatrix_add_csc(pangulu_smatrix *a) pangulu_free(__FILE__, __LINE__, index_rowpointer); } +// void pangulu_origin_smatrix_add_csc(pangulu_origin_smatrix *a) +// { +// // add csc memory +// pangulu_exblock_ptr nnzA = a->rowpointer[a->row]; +// pangulu_exblock_idx n = a->row; +// char *now_malloc_space = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1) + sizeof(pangulu_exblock_idx) * nnzA + sizeof(calculate_type) * nnzA); + +// pangulu_exblock_ptr *rowpointer = (pangulu_exblock_ptr *)now_malloc_space; +// pangulu_exblock_idx *columnindex = (pangulu_exblock_idx *)(now_malloc_space + sizeof(pangulu_exblock_ptr) * (n + 1)); +// calculate_type *value = (calculate_type *)(now_malloc_space + sizeof(pangulu_exblock_ptr) * (n + 1) + sizeof(pangulu_exblock_idx) * nnzA); +// pangulu_exblock_ptr *csc_to_csr_index = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * nnzA); +// for (pangulu_exblock_ptr i = 0; i < nnzA; i++) +// { +// value[i] = 0.0; +// } + +// for (pangulu_exblock_idx i = 0; i < (n + 1); i++) +// { +// rowpointer[i] = 0; +// } +// for (pangulu_exblock_ptr i = 0; i < nnzA; i++) +// { +// rowpointer[a->columnindex[i] + 1]++; +// } +// for (pangulu_exblock_idx i = 0; i < n; i++) +// { +// rowpointer[i + 1] += rowpointer[i]; +// } +// pangulu_exblock_ptr *index_rowpointer = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); +// for (pangulu_exblock_idx i = 0; i < n; i++) +// { +// index_rowpointer[i] = rowpointer[i]; +// } +// for (pangulu_exblock_idx i = 0; i < n; i++) +// { +// for (pangulu_exblock_ptr j = a->rowpointer[i]; j < a->rowpointer[i + 1]; j++) +// { + +// pangulu_exblock_idx col = a->columnindex[j]; +// pangulu_exblock_ptr index = index_rowpointer[col]; +// columnindex[index] = i; +// value[index] = a->value[j]; +// csc_to_csr_index[index] = j; +// index_rowpointer[col]++; +// } +// } +// a->columnpointer = rowpointer; +// a->rowindex = columnindex; +// a->value_csc = value; +// a->csc_to_csr_index = csc_to_csr_index; +// pangulu_free(__FILE__, __LINE__, index_rowpointer); +// } + void pangulu_origin_smatrix_add_csc(pangulu_origin_smatrix *a) { - // add csc moemory pangulu_exblock_ptr nnzA = a->rowpointer[a->row]; pangulu_exblock_idx n = a->row; char *now_malloc_space = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1) + sizeof(pangulu_exblock_idx) * nnzA + sizeof(calculate_type) * nnzA); - - pangulu_exblock_ptr *rowpointer = (pangulu_exblock_ptr *)now_malloc_space; - pangulu_exblock_idx *columnindex = (pangulu_exblock_idx *)(now_malloc_space + sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_ptr *columnpointer = (pangulu_exblock_ptr *)now_malloc_space; + pangulu_exblock_idx *rowindex = (pangulu_exblock_idx *)(now_malloc_space + sizeof(pangulu_exblock_ptr) * (n + 1)); calculate_type *value = (calculate_type *)(now_malloc_space + sizeof(pangulu_exblock_ptr) * (n + 1) + sizeof(pangulu_exblock_idx) * nnzA); pangulu_exblock_ptr *csc_to_csr_index = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * nnzA); - for (pangulu_exblock_ptr i = 0; i < nnzA; i++) - { - value[i] = 0.0; - } + pangulu_exblock_ptr *index_columnpointer = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + #pragma omp parallel for for (pangulu_exblock_idx i = 0; i < (n + 1); i++) { - rowpointer[i] = 0; + columnpointer[i] = 0; } for (pangulu_exblock_ptr i = 0; i < nnzA; i++) { - rowpointer[a->columnindex[i] + 1]++; + columnpointer[a->columnindex[i] + 1]++; } for (pangulu_exblock_idx i = 0; i < n; i++) { - rowpointer[i + 1] += rowpointer[i]; + columnpointer[i + 1] += columnpointer[i]; } - pangulu_exblock_ptr *index_rowpointer = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + #pragma omp parallel for for (pangulu_exblock_idx i = 0; i < n; i++) { - index_rowpointer[i] = rowpointer[i]; + index_columnpointer[i] = columnpointer[i]; } for (pangulu_exblock_idx i = 0; i < n; i++) { for (pangulu_exblock_ptr j = a->rowpointer[i]; j < a->rowpointer[i + 1]; j++) { - pangulu_exblock_idx col = a->columnindex[j]; - pangulu_exblock_ptr index = index_rowpointer[col]; - columnindex[index] = i; + pangulu_exblock_ptr index = index_columnpointer[col]; + rowindex[index] = i; value[index] = a->value[j]; csc_to_csr_index[index] = j; - index_rowpointer[col]++; + index_columnpointer[col]++; } } - a->columnpointer = rowpointer; - a->rowindex = columnindex; + a->columnpointer = columnpointer; + a->rowindex = rowindex; a->value_csc = value; a->csc_to_csr_index = csc_to_csr_index; - pangulu_free(__FILE__, __LINE__, index_rowpointer); + pangulu_free(__FILE__, __LINE__, index_columnpointer); } void pangulu_malloc_pangulu_smatrix_csc(pangulu_smatrix *s, diff --git a/src/pangulu_numeric.c b/src/pangulu_numeric.c index af4c32e..5a9a941 100644 --- a/src/pangulu_numeric.c +++ b/src/pangulu_numeric.c @@ -23,7 +23,7 @@ void pangulu_solve_a_to_lu(pangulu_int64_t level, pangulu_int64_t row, pangulu_i pangulu_getrf_interface(a, l, u, calculate_L, calculate_U); #ifdef GPU_TSTRF - pangulu_transport_pangulu_smatrix_csc_to_csr(u); + pangulu_transpose_pangulu_smatrix_csc_to_csr(u); #endif #ifdef OVERLAP diff --git a/src/pangulu_preprocessing.c b/src/pangulu_preprocessing.c index b6ded41..5113d6d 100644 --- a/src/pangulu_preprocessing.c +++ b/src/pangulu_preprocessing.c @@ -10,6 +10,36 @@ void pangulu_preprocessing(pangulu_block_common *block_common, pangulu_origin_smatrix *reorder_matrix, pangulu_int64_t nthread) { + struct timeval start_time; + pangulu_exblock_idx n = block_common->n; + pangulu_exblock_idx n_loc = 0; + pangulu_exblock_idx nb = block_common->nb; + pangulu_exblock_idx block_length = block_common->block_length; + pangulu_int32_t rank = block_common->rank; + pangulu_int32_t nproc = block_common->sum_rank_size; + + pangulu_exblock_ptr* distcsc_proc_nnzptr; + pangulu_exblock_ptr* distcsc_symbolic_proc_nnzptr; + pangulu_exblock_ptr* distcsc_pointer; + pangulu_exblock_idx* distcsc_index; + calculate_type* distcsc_value; + pangulu_exblock_ptr* bcsc_nofill_pointer; + pangulu_exblock_idx* bcsc_nofill_index; + pangulu_exblock_ptr* bcsc_nofill_blknnzptr; + pangulu_inblock_ptr** bcsc_nofill_inblk_pointers; + pangulu_inblock_idx** bcsc_nofill_inblk_indeces; + calculate_type** bcsc_nofill_inblk_values; + pangulu_exblock_ptr* bcsc_pointer; + pangulu_exblock_idx* bcsc_index; + pangulu_exblock_ptr* bcsc_blknnzptr; + pangulu_inblock_ptr** bcsc_inblk_pointers; + pangulu_inblock_idx** bcsc_inblk_indeces; + calculate_type** bcsc_inblk_values; + + pangulu_exblock_ptr* bcsc_related_pointer; + pangulu_exblock_idx* bcsc_related_index; + pangulu_uint64_t* bcsc_related_draft_info; + const pangulu_int64_t preprocess_ompnum = nthread; pangulu_int64_t preprocess_ompnum_sort = preprocess_ompnum; pangulu_int64_t preprocess_ompnum_fill_columnindex = preprocess_ompnum; @@ -17,16 +47,14 @@ void pangulu_preprocessing(pangulu_block_common *block_common, pangulu_int64_t preprocess_ompnum_separate_block = preprocess_ompnum; pangulu_int64_t preprocess_ompnum_send_block = preprocess_ompnum; - pangulu_int64_t n = block_common->n; pangulu_int32_t p = block_common->p; pangulu_int32_t q = block_common->q; - pangulu_int32_t nb = block_common->nb; pangulu_block_info_pool *BIP = block_smatrix->BIP; pangulu_exblock_ptr *symbolic_rowpointer = NULL; pangulu_exblock_idx *symbolic_columnindex = NULL; - pangulu_int32_t block_length = block_common->block_length; + bind_to_core((rank) % sysconf(_SC_NPROCESSORS_ONLN)); // rank 0 only pangulu_int64_t block_num; @@ -114,72 +142,145 @@ void pangulu_preprocessing(pangulu_block_common *block_common, MPI_Bcast((char *)(BIP->data), sizeof(pangulu_block_info) * BIP->length, MPI_CHAR, 0, MPI_COMM_WORLD); // containing block_smatrix_nnzA_num MPI_Bcast(BIP->block_map, PANGULU_BIP_MAP_LENGTH(BIP->index_upper_bound), MPI_PANGULU_INT64_T, 0, MPI_COMM_WORLD); // containing block_smatrix_nnzA_num - if (rank == 0) - { - - for (pangulu_exblock_idx i = 0; i < n; i++) - { - for (pangulu_exblock_ptr j = reorder_matrix->rowpointer[i]; j < reorder_matrix->rowpointer[i + 1]; j++) - { - pangulu_exblock_idx block_row = i / nb; - pangulu_exblock_idx block_col = (reorder_matrix->columnindex[j]) / nb; - } - } - A_nnz_rowpointer_num = 0; - - for (pangulu_int32_t offset_block_row = 0; offset_block_row < p; offset_block_row++) - { - for (pangulu_int32_t offset_block_col = 0; offset_block_col < q; offset_block_col++) - { - for (pangulu_exblock_idx i = offset_block_row; i < block_length; i += p) - { - for (pangulu_exblock_idx j = offset_block_col; j < block_length; j += q) - { - if (pangulu_bip_get(i * block_length + j, BIP)->block_smatrix_nnza_num != 0) - { - A_nnz_rowpointer_num++; - } - } - } - } - } - } + if(rank == 0){ + pangulu_time_start(&start_time); + pangulu_convert_csr_to_csc( + 1, n, + &reorder_matrix->rowpointer, + &reorder_matrix->columnindex, + &reorder_matrix->value, + &reorder_matrix->columnpointer, + &reorder_matrix->rowindex, + &reorder_matrix->value_csc + ); + printf("[PanguLU Info] 6 PanguLU transpose reordered matrix time is %lf s.\n", pangulu_time_stop(&start_time)); + distcsc_pointer = reorder_matrix->columnpointer; + distcsc_index = reorder_matrix->rowindex; + distcsc_value = reorder_matrix->value_csc; + reorder_matrix->columnpointer = NULL; + reorder_matrix->rowindex = NULL; + reorder_matrix->value_csc = NULL; + } + + pangulu_cm_sync(); + + double time_dist_prep = 0; + + if(rank == 0){ + pangulu_time_start(&start_time); + } + // distribute to processes + pangulu_cm_distribute_csc_to_distcsc( + 0, 1, &n, nb, &nproc, &n_loc, + &distcsc_proc_nnzptr, + &distcsc_pointer, + &distcsc_index, + &distcsc_value + ); + + pangulu_cm_sync(); + + pangulu_cm_distribute_distcsc_to_distbcsc( + 1, 1, n, n_loc, nb, + distcsc_proc_nnzptr, + distcsc_pointer, + distcsc_index, + distcsc_value, + &bcsc_nofill_pointer, + &bcsc_nofill_index, + &bcsc_nofill_blknnzptr, + &bcsc_nofill_inblk_pointers, + &bcsc_nofill_inblk_indeces, + &bcsc_nofill_inblk_values + ); + + pangulu_cm_sync(); + + if(rank == 0){ + time_dist_prep += pangulu_time_stop(&start_time); + } + + if(rank == 0){ + // generate full symbolic struct + pangulu_sort_exblock_struct(n, block_smatrix->symbolic_rowpointer, block_smatrix->symbolic_columnindex, 0); + pangulu_time_start(&start_time); + pangulu_convert_ordered_halfsymcsc_to_csc_struct( + 1, 0, n, + &block_smatrix->symbolic_rowpointer, + &block_smatrix->symbolic_columnindex, + &block_smatrix->symbolic_rowpointer, + &block_smatrix->symbolic_columnindex + ); + printf("[PanguLU Info] 7 PanguLU generate full symbolic matrix time is %lf s.\n", pangulu_time_stop(&start_time)); + } + + pangulu_cm_sync_asym(0); + pangulu_cm_sync(); + + if(rank == 0){ + pangulu_time_start(&start_time); + } + + // distribute to processes + pangulu_cm_distribute_csc_to_distcsc( + 0, 1, &n, nb, &nproc, &n_loc, + &distcsc_symbolic_proc_nnzptr, + &block_smatrix->symbolic_rowpointer, + &block_smatrix->symbolic_columnindex, + NULL + ); + + pangulu_cm_sync(); + + // pangulu_sort_exblock_struct(n_loc, block_smatrix->symbolic_rowpointer, block_smatrix->symbolic_columnindex, 0); + + // pangulu_cm_sync_asym(nproc - 1); + + pangulu_cm_distribute_distcsc_to_distbcsc( + 1, 1, n, n_loc, nb, + distcsc_symbolic_proc_nnzptr, + block_smatrix->symbolic_rowpointer, + block_smatrix->symbolic_columnindex, + NULL, + &bcsc_pointer, + &bcsc_index, + &bcsc_blknnzptr, + &bcsc_inblk_pointers, + &bcsc_inblk_indeces, + &bcsc_inblk_values + ); + + pangulu_cm_sync(); + + pangulu_convert_bcsc_fill_value_to_struct( + 1, n, nb, + bcsc_nofill_pointer, + bcsc_nofill_index, + bcsc_nofill_blknnzptr, + bcsc_nofill_inblk_pointers, + bcsc_nofill_inblk_indeces, + bcsc_nofill_inblk_values, + bcsc_pointer, + bcsc_index, + bcsc_blknnzptr, + bcsc_inblk_pointers, + bcsc_inblk_indeces, + bcsc_inblk_values + ); + bcsc_nofill_pointer = NULL; + bcsc_nofill_index = NULL; + bcsc_nofill_blknnzptr = NULL; + bcsc_nofill_inblk_pointers = NULL; + bcsc_nofill_inblk_indeces = NULL; + bcsc_nofill_inblk_values = NULL; pangulu_bcast_vector(block_smatrix_non_zero_vector_L, block_length, 0); pangulu_bcast_vector(block_smatrix_non_zero_vector_U, block_length, 0); - every_rank_block_num[rank] = 0; - for (pangulu_exblock_idx row = 0; row < block_length; row++) - { - for (pangulu_exblock_idx col = 0; col < block_length; col++) - { - if (pangulu_bip_get(row * block_length + col, BIP)->block_smatrix_nnza_num != 0) - { - int32_t now_rank = (row % p) * q + (col % q); - if (now_rank == rank) - { - every_rank_block_num[rank]++; - } - } - } - } - - every_rank_block_nnz[rank] = 0; - for (pangulu_exblock_idx row = 0; row < block_length; row++) - { - for (pangulu_exblock_idx col = 0; col < block_length; col++) - { - if (pangulu_bip_get(row * block_length + col, BIP)->block_smatrix_nnza_num != 0) - { - int32_t now_rank = (row % p) * q + (col % q); - if (now_rank == rank) - { - every_rank_block_nnz[rank] += pangulu_bip_get(row * block_length + col, BIP)->block_smatrix_nnza_num; - } - } - } - } + every_rank_block_num[rank] = bcsc_pointer[block_length]; + every_rank_block_nnz[rank] = bcsc_blknnzptr[bcsc_pointer[block_length]]; + pangulu_free(__FILE__, __LINE__, bcsc_blknnzptr); if (rank == 0) { @@ -215,11 +316,8 @@ void pangulu_preprocessing(pangulu_block_common *block_common, } } - if (rank != 0) - { - pangulu_free(__FILE__, __LINE__, every_rank_block_num); - pangulu_free(__FILE__, __LINE__, every_rank_block_nnz); - } + pangulu_free(__FILE__, __LINE__, every_rank_block_num); + pangulu_free(__FILE__, __LINE__, every_rank_block_nnz); pangulu_smatrix *Big_smatrix_value = (pangulu_smatrix *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_smatrix) * current_rank_block_count); for (pangulu_int64_t i = 0; i < current_rank_block_count; i++) @@ -229,472 +327,32 @@ void pangulu_preprocessing(pangulu_block_common *block_common, current_rank_block_count = 0; current_rank_nnz_count = 0; - pangulu_int64_t max_nnz = 0; pangulu_exblock_ptr nzblk_current_rank = 0; pangulu_exblock_ptr nnz_current_rank = 0; - char *blkcsr_current_rank = NULL; - char *blocks_current_rank = NULL; - if (rank == 0) + for (pangulu_exblock_idx bcol = 0; bcol < block_length; bcol++) { - struct timeval fill_start, fill_end; - struct timeval fill_all_start, fill_all_end; - - gettimeofday(&fill_all_start, NULL); - gettimeofday(&fill_start, NULL); - pangulu_exblock_ptr *symbolic_full_rowpointer = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); - pangulu_exblock_idx *symbolic_full_columnindex = (pangulu_exblock_idx *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * block_smatrix->symbolic_nnz); - pangulu_int64_t *symbolic_aid_array = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * n * (preprocess_ompnum_fill_columnindex + 1)); - memset(symbolic_aid_array, 0, sizeof(pangulu_int64_t) * n * (preprocess_ompnum_fill_columnindex + 1)); - memset(symbolic_full_rowpointer, 0, sizeof(pangulu_int64_t) * (n + 1)); - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); - for (int32_t row = 0; row < n; row++) + for (pangulu_exblock_ptr bidx = bcsc_pointer[bcol]; bidx < bcsc_pointer[bcol + 1]; bidx++) { - for (pangulu_int64_t j = symbolic_rowpointer[row]; j < symbolic_rowpointer[row + 1]; j++) - { - int32_t column = symbolic_columnindex[j]; - symbolic_aid_array[((row % preprocess_ompnum_fill_columnindex) + 1) * n + column]++; - if (row != column) - { - symbolic_full_rowpointer[column + 1]++; - } - } - } - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); - for (int j = 0; j < n; j++) - { - for (int i = 1; i < preprocess_ompnum_fill_columnindex + 1; i++) - { - symbolic_aid_array[i * n + j] += symbolic_aid_array[(i - 1) * n + j]; - } - } - for (pangulu_int32_t row = 1; row < n + 1; row++) - { - for (int i = 0; i < preprocess_ompnum_fill_columnindex + 1; i++) - { - symbolic_aid_array[i * n + (row - 1)] += symbolic_full_rowpointer[row - 1]; - } - symbolic_full_rowpointer[row] = symbolic_full_rowpointer[row] + symbolic_full_rowpointer[row - 1] + (symbolic_rowpointer[row] - symbolic_rowpointer[row - 1]); + pangulu_exblock_idx brow = bcsc_index[bidx]; + pangulu_smatrix *current = &Big_smatrix_value[current_rank_block_count]; + current->row = nb; + current->column = nb; + current->nnz = bcsc_inblk_pointers[bidx][nb]; + current->columnpointer = bcsc_inblk_pointers[bidx]; + current->rowindex = bcsc_inblk_indeces[bidx]; + current->value_csc = bcsc_inblk_values[bidx]; + pangulu_bip_set(brow * block_length + bcol, BIP)->mapper_a = current_rank_block_count; + current_rank_block_count++; } - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); - for (pangulu_int32_t row = 0; row < n; row++) - { - memcpy(&symbolic_full_columnindex[symbolic_full_rowpointer[row + 1] - (symbolic_rowpointer[row + 1] - symbolic_rowpointer[row])], &symbolic_columnindex[symbolic_rowpointer[row]], sizeof(pangulu_int32_t) * (symbolic_rowpointer[row + 1] - symbolic_rowpointer[row])); - } - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); -#pragma omp parallel num_threads(preprocess_ompnum_fill_columnindex) - { - int tid = omp_get_thread_num(); - for (pangulu_int32_t row = tid; row < n; row += preprocess_ompnum_fill_columnindex) - { - for (pangulu_int64_t j = symbolic_rowpointer[row]; j < symbolic_rowpointer[row + 1]; j++) - { - int32_t column = symbolic_columnindex[j]; - symbolic_full_columnindex[symbolic_aid_array[tid * n + column]++] = row; - } - } - } - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); - const int row_count_of_one_chunk = 500; - int total_chunk_count = (n + row_count_of_one_chunk + 1) / row_count_of_one_chunk; - pangulu_int32_t *chunks_of_omp_rank = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * total_chunk_count * preprocess_ompnum_sort); - pangulu_int32_t *chunk_count_of_omp_rank = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * preprocess_ompnum_sort); - pangulu_int64_t *omp_rank_total_nnz = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * preprocess_ompnum_sort); - memset(chunk_count_of_omp_rank, 0, sizeof(pangulu_int32_t) * preprocess_ompnum_sort); - memset(omp_rank_total_nnz, 0, sizeof(pangulu_int64_t) * preprocess_ompnum_sort); - for (pangulu_int32_t chunk_id = 0; chunk_id < total_chunk_count; chunk_id++) - { - pangulu_int64_t chunk_nnz = symbolic_full_rowpointer[PANGULU_MIN((chunk_id + 1) * row_count_of_one_chunk, n)] - symbolic_full_rowpointer[chunk_id * row_count_of_one_chunk]; - pangulu_int64_t min_nnz = 0x7FFFFFFFFFFFFFFF; - int min_nnz_rank = 0; - for (int i = 0; i < preprocess_ompnum_sort; i++) - { - if (omp_rank_total_nnz[i] < min_nnz) - { - min_nnz = omp_rank_total_nnz[i]; - min_nnz_rank = i; - } - } - omp_rank_total_nnz[min_nnz_rank] += chunk_nnz; - chunks_of_omp_rank[min_nnz_rank * total_chunk_count + chunk_count_of_omp_rank[min_nnz_rank]] = chunk_id; - chunk_count_of_omp_rank[min_nnz_rank]++; - } - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); -#pragma omp parallel num_threads(preprocess_ompnum_sort) - { - int omp_size = omp_get_num_threads(); - int omp_tid = omp_get_thread_num(); - for (pangulu_int32_t i = 0; i < chunk_count_of_omp_rank[omp_tid]; i++) - { - for (pangulu_int32_t row = chunks_of_omp_rank[omp_tid * total_chunk_count + i] * row_count_of_one_chunk; row < PANGULU_MIN((chunks_of_omp_rank[omp_tid * total_chunk_count + i] + 1) * row_count_of_one_chunk, n); row++) - { - qsort(&symbolic_full_columnindex[symbolic_full_rowpointer[row]], symbolic_full_rowpointer[row + 1] - symbolic_full_rowpointer[row], sizeof(pangulu_int32_t), cmp_int32t_asc); - } - } - } - gettimeofday(&fill_end, NULL); - gettimeofday(&fill_start, NULL); - pangulu_free(__FILE__, __LINE__, chunks_of_omp_rank); - pangulu_free(__FILE__, __LINE__, chunk_count_of_omp_rank); - pangulu_free(__FILE__, __LINE__, omp_rank_total_nnz); - pangulu_free(__FILE__, __LINE__, symbolic_aid_array); - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_start, NULL); - pangulu_int64_t nnz = symbolic_full_rowpointer[n]; - int bit_length = (block_length + 31) / 32; - - pangulu_int64_t avg_nnz = (nnz + preprocess_ompnum_separate_block - 1) / preprocess_ompnum_separate_block; - pangulu_int64_t *block_row_nnz_pt = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * (block_length + 1)); - for (int i = 0; i < block_length; i++) - { - block_row_nnz_pt[i] = symbolic_full_rowpointer[i * nb]; - } - block_row_nnz_pt[block_length] = symbolic_full_rowpointer[n]; - int *pt = (int *)pangulu_malloc(__FILE__, __LINE__, sizeof(int) * (preprocess_ompnum_separate_block + 1)); - pt[0] = 0; - for (int i = 1; i < preprocess_ompnum_separate_block + 1; i++) - { - pt[i] = binarylowerbound(block_row_nnz_pt, block_length, avg_nnz * i); - } - - pangulu_int64_t *block_row_pt = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * (block_length + 1)); - memset(block_row_pt, 0, sizeof(pangulu_int64_t) * (block_length + 1)); - - unsigned int *bit_array = (unsigned int *)pangulu_malloc(__FILE__, __LINE__, sizeof(unsigned int) * bit_length * preprocess_ompnum_separate_block); - -#pragma omp parallel num_threads(preprocess_ompnum_separate_block) - { - int tid = omp_get_thread_num(); - unsigned int *tmp_bit = bit_array + bit_length * tid; - - for (int level = pt[tid]; level < pt[tid + 1]; level++) - { - memset(tmp_bit, 0, sizeof(unsigned int) * bit_length); - - int start_row = level * nb; - int end_row = ((level + 1) * nb) < n ? ((level + 1) * nb) : n; - - for (int rid = start_row; rid < end_row; rid++) - { - for (pangulu_int64_t idx = symbolic_full_rowpointer[rid]; idx < symbolic_full_rowpointer[rid + 1]; idx++) - { - pangulu_int32_t colidx = symbolic_full_columnindex[idx]; - pangulu_int32_t block_cid = colidx / nb; - setbit(tmp_bit[block_cid / 32], block_cid % 32); - } - } - - pangulu_int64_t tmp_blocknum = 0; - for (int i = 0; i < bit_length; i++) - { - tmp_blocknum += __builtin_popcount(tmp_bit[i]); - } - - block_row_pt[level] = tmp_blocknum; - } - } - exclusive_scan_1(block_row_pt, block_length + 1); - block_num = block_row_pt[block_length]; - - block_nnz_pt = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * (block_num + 1)); - memset(block_nnz_pt, 0, sizeof(pangulu_int64_t) * (block_num + 1)); - pangulu_int32_t *block_col_idx = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * block_num); - - int *count_array = (int *)pangulu_malloc(__FILE__, __LINE__, sizeof(int) * block_length * preprocess_ompnum_separate_block); - -#pragma omp parallel num_threads(preprocess_ompnum_separate_block) - { - int tid = omp_get_thread_num(); - unsigned int *tmp_bit = bit_array + bit_length * tid; - int *tmp_count = count_array + block_length * tid; - - for (int level = pt[tid]; level < pt[tid + 1]; level++) - { - memset(tmp_bit, 0, sizeof(unsigned int) * bit_length); - memset(tmp_count, 0, sizeof(int) * block_length); - - pangulu_int64_t *cur_block_nnz_pt = block_nnz_pt + block_row_pt[level]; - pangulu_int32_t *cur_block_col_idx = block_col_idx + block_row_pt[level]; - - int start_row = level * nb; - int end_row = ((level + 1) * nb) < n ? ((level + 1) * nb) : n; - - for (int rid = start_row; rid < end_row; rid++) - { - for (pangulu_int64_t idx = symbolic_full_rowpointer[rid]; idx < symbolic_full_rowpointer[rid + 1]; idx++) - { - pangulu_int32_t colidx = symbolic_full_columnindex[idx]; - pangulu_int32_t block_cid = colidx / nb; - setbit(tmp_bit[block_cid / 32], block_cid % 32); - tmp_count[block_cid]++; - } - } - - pangulu_int64_t cnt = 0; - for (int i = 0; i < block_length; i++) - { - if (getbit(tmp_bit[i / 32], i % 32)) - { - cur_block_nnz_pt[cnt] = tmp_count[i]; - cur_block_col_idx[cnt] = i; - cnt++; - } - } - } - } - exclusive_scan_1(block_nnz_pt, block_num + 1); - block_csr = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_ptr) * (nb + 1) * block_num + sizeof(pangulu_inblock_idx) * nnz + sizeof(calculate_type) * nnz); - -#pragma omp parallel num_threads(preprocess_ompnum_separate_block) - { - int tid = omp_get_thread_num(); - int *tmp_count = count_array + block_length * tid; - - for (int level = pt[tid]; level < pt[tid + 1]; level++) - { - - memset(tmp_count, 0, sizeof(int) * block_length); - - for (pangulu_int64_t blc = block_row_pt[level]; blc < block_row_pt[level + 1]; blc++) - { - pangulu_int64_t tmp_stride = blc * (nb + 1) * sizeof(pangulu_inblock_ptr) + block_nnz_pt[blc] * (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)); - pangulu_inblock_ptr *cur_csr_rpt = (pangulu_inblock_ptr *)(block_csr + tmp_stride); - - memset(cur_csr_rpt, 0, sizeof(pangulu_inblock_ptr) * (nb + 1)); - } - - int start_row = level * nb; - int end_row = ((level + 1) * nb) < n ? ((level + 1) * nb) : n; - - for (int rid = start_row, r_in_blc = 0; rid < end_row; rid++, r_in_blc++) - { - pangulu_int64_t cur_block_idx = block_row_pt[level]; - - pangulu_int64_t arr_len = cur_block_idx * (nb + 1) * sizeof(pangulu_inblock_ptr) + block_nnz_pt[cur_block_idx] * (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)); - pangulu_inblock_ptr *cur_block_rowptr = (pangulu_inblock_ptr *)(block_csr + arr_len); - pangulu_inblock_idx *cur_block_colidx = (pangulu_inblock_idx *)(block_csr + arr_len + (nb + 1) * sizeof(pangulu_inblock_ptr)); - calculate_type *cur_block_value = (calculate_type *)(block_csr + arr_len + (nb + 1) * sizeof(pangulu_inblock_ptr) + (block_nnz_pt[cur_block_idx + 1] - block_nnz_pt[cur_block_idx]) * sizeof(pangulu_inblock_idx)); - - pangulu_exblock_ptr reorder_matrix_idx = reorder_matrix->rowpointer[rid]; - pangulu_exblock_ptr reorder_matrix_idx_ub = reorder_matrix->rowpointer[rid + 1]; - for (pangulu_exblock_ptr idx = symbolic_full_rowpointer[rid]; idx < symbolic_full_rowpointer[rid + 1]; idx++) - { - pangulu_exblock_idx colidx = symbolic_full_columnindex[idx]; - pangulu_exblock_idx block_cid = colidx / nb; - if (block_col_idx[cur_block_idx] != block_cid) - { - cur_block_idx = binarysearch(block_col_idx, cur_block_idx, block_row_pt[level + 1], block_cid); - - arr_len = cur_block_idx * (nb + 1) * sizeof(pangulu_inblock_ptr) + block_nnz_pt[cur_block_idx] * (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)); - cur_block_rowptr = (pangulu_inblock_ptr *)(block_csr + arr_len); - cur_block_colidx = (pangulu_inblock_idx *)(block_csr + arr_len + (nb + 1) * sizeof(pangulu_inblock_ptr)); - cur_block_value = (calculate_type *)(block_csr + arr_len + (nb + 1) * sizeof(pangulu_inblock_ptr) + (block_nnz_pt[cur_block_idx + 1] - block_nnz_pt[cur_block_idx]) * sizeof(pangulu_inblock_idx)); - } - if ((reorder_matrix->columnindex[reorder_matrix_idx] == colidx) && (reorder_matrix_idx < reorder_matrix_idx_ub)) - { - cur_block_value[tmp_count[block_cid]] = reorder_matrix->value[reorder_matrix_idx]; - reorder_matrix_idx++; - } - else - { - cur_block_value[tmp_count[block_cid]] = 0.0; - } - cur_block_colidx[tmp_count[block_cid]++] = colidx % nb; - cur_block_rowptr[r_in_blc]++; - } - } - - for (pangulu_int64_t blc = block_row_pt[level]; blc < block_row_pt[level + 1]; blc++) - { - pangulu_int64_t tmp_stride = blc * (nb + 1) * sizeof(pangulu_inblock_ptr) + block_nnz_pt[blc] * (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)); - pangulu_inblock_ptr *cur_csr_rpt = (pangulu_inblock_ptr *)(block_csr + tmp_stride); - exclusive_scan_3(cur_csr_rpt, nb + 1); - } - } - } - - gettimeofday(&fill_end, NULL); - pangulu_free(__FILE__, __LINE__, symbolic_full_rowpointer); - pangulu_free(__FILE__, __LINE__, symbolic_full_columnindex); - - mpi_barrier_asym(MPI_COMM_WORLD, 0, 1e5); - - gettimeofday(&fill_start, NULL); - pangulu_exblock_ptr *calculated_nzblk_count_each_rank = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * sum_rank_size); - memset(calculated_nzblk_count_each_rank, 0, sizeof(pangulu_exblock_ptr) * sum_rank_size); - char *blkcsr_all_rank = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (block_length + 1) * sum_rank_size + (sizeof(pangulu_exblock_idx) /*blk_colidx*/ + sizeof(pangulu_inblock_ptr) /*blk_value(nnz_in_block)*/) * block_num); - char **blkcsr_each_rank = (char **)pangulu_malloc(__FILE__, __LINE__, sizeof(char *) * sum_rank_size); - pangulu_int64_t counted_block = 0; - for (int i = 0; i < sum_rank_size; i++) - { - blkcsr_each_rank[i] = blkcsr_all_rank + sizeof(pangulu_exblock_ptr) * (block_length + 1) * i + (sizeof(pangulu_exblock_idx) /*blk_colidx*/ + sizeof(pangulu_inblock_ptr) /*blk_value(nnz_in_block)*/) * counted_block; - counted_block += every_rank_block_num[i]; - } - - for (int target_rank = 0; target_rank < sum_rank_size; target_rank++) - { - pangulu_exblock_ptr *blkcsr_rowptr = (pangulu_exblock_ptr *)blkcsr_each_rank[target_rank]; - blkcsr_rowptr[0] = 0; - } - for (int brow = 0; brow < block_length; brow++) - { - for (pangulu_int64_t bidx = block_row_pt[brow]; bidx < block_row_pt[brow + 1]; bidx++) - { - int bcol = block_col_idx[bidx]; - int target_rank = (brow % p) * q + (bcol % q); - - pangulu_exblock_idx *blkcsr_colidx = (pangulu_exblock_idx *)(blkcsr_each_rank[target_rank] + sizeof(pangulu_exblock_ptr) * (block_length + 1)); - pangulu_inblock_ptr *blkcsr_value_blknnz = (pangulu_inblock_ptr *)(blkcsr_each_rank[target_rank] + sizeof(pangulu_exblock_ptr) * (block_length + 1) + sizeof(pangulu_exblock_idx) * every_rank_block_num[target_rank]); - - pangulu_exblock_ptr bidx_in_target_rank = calculated_nzblk_count_each_rank[target_rank]; - blkcsr_colidx[bidx_in_target_rank] = bcol; - blkcsr_value_blknnz[bidx_in_target_rank] = block_nnz_pt[bidx + 1] - block_nnz_pt[bidx]; - - calculated_nzblk_count_each_rank[target_rank]++; - } - for (int target_rank = 0; target_rank < sum_rank_size; target_rank++) - { - pangulu_exblock_ptr *blkcsr_rowptr = (pangulu_exblock_ptr *)blkcsr_each_rank[target_rank]; - blkcsr_rowptr[brow + 1] = calculated_nzblk_count_each_rank[target_rank]; - } - } - pangulu_free(__FILE__, __LINE__, every_rank_block_num); - - pangulu_exblock_idx *sent_block_count_each_rank = (pangulu_exblock_idx *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * sum_rank_size); - memset(sent_block_count_each_rank, 0, sizeof(pangulu_exblock_idx) * sum_rank_size); -#pragma omp parallel num_threads(preprocess_ompnum_send_block) - { - int tid = omp_get_thread_num(); - int nthread = omp_get_num_threads(); - for (int target_rank = tid; target_rank < sum_rank_size; target_rank += nthread) - { - if (target_rank != 0) - { - MPI_Send(calculated_nzblk_count_each_rank + target_rank, 1, MPI_PANGULU_EXBLOCK_PTR, target_rank, 0xCAFE + 1, MPI_COMM_WORLD); - MPI_Send(every_rank_block_nnz + target_rank, 1, MPI_PANGULU_INT64_T, target_rank, 0xCAFE + 2, MPI_COMM_WORLD); - MPI_Send(blkcsr_each_rank[target_rank], sizeof(pangulu_exblock_ptr) * (block_length + 1) + (sizeof(pangulu_exblock_idx) + sizeof(pangulu_inblock_ptr)) * calculated_nzblk_count_each_rank[target_rank], MPI_CHAR, target_rank, 0xCAFE + 3, MPI_COMM_WORLD); - } - else - { - nzblk_current_rank = calculated_nzblk_count_each_rank[target_rank]; - nnz_current_rank = every_rank_block_nnz[target_rank]; - blkcsr_current_rank = blkcsr_each_rank[0]; - blocks_current_rank = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_ptr) * (nb + 1) * nzblk_current_rank + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * nnz_current_rank); - } - pangulu_int64_t blocks_current_rank_receive_offset = 0; - for (pangulu_exblock_idx brow = 0; brow < block_length; brow++) - { - if (brow % p != target_rank / q) - { - continue; - } - for (pangulu_exblock_ptr bidx = block_row_pt[brow]; bidx < block_row_pt[brow + 1]; bidx++) - { - pangulu_exblock_idx bcol = block_col_idx[bidx]; - if (bcol % q != target_rank % q) - { - continue; - } - pangulu_int64_t block_byte_offset = sizeof(pangulu_inblock_ptr) * (bidx * (nb + 1)) + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * block_nnz_pt[bidx]; - if (target_rank != 0) - { - MPI_Send(block_csr + block_byte_offset, sizeof(pangulu_inblock_ptr) * (nb + 1) + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * (block_nnz_pt[bidx + 1] - block_nnz_pt[bidx]), MPI_CHAR, target_rank, sent_block_count_each_rank[target_rank], MPI_COMM_WORLD); - sent_block_count_each_rank[target_rank]++; - } - else - { - memcpy(blocks_current_rank + blocks_current_rank_receive_offset, block_csr + block_byte_offset, sizeof(pangulu_inblock_ptr) * (nb + 1) + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * (block_nnz_pt[bidx + 1] - block_nnz_pt[bidx])); - - pangulu_smatrix *current = &Big_smatrix_value[current_rank_block_count]; - current->row = nb; - current->column = nb; - current->rowpointer = (pangulu_inblock_ptr *)(blocks_current_rank + blocks_current_rank_receive_offset); - current->nnz = current->rowpointer[nb]; - current->columnindex = (pangulu_inblock_idx *)(blocks_current_rank + blocks_current_rank_receive_offset + sizeof(pangulu_inblock_ptr) * (nb + 1)); - current->value = (calculate_type *)(blocks_current_rank + blocks_current_rank_receive_offset + sizeof(pangulu_inblock_ptr) * (nb + 1) + sizeof(pangulu_inblock_idx) * current->nnz); - - pangulu_bip_set(brow * block_length + bcol, BIP)->mapper_a = current_rank_block_count; - - blocks_current_rank_receive_offset += sizeof(pangulu_inblock_ptr) * (nb + 1) + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * (block_nnz_pt[bidx + 1] - block_nnz_pt[bidx]); - current_rank_block_count++; - } - } - } - } - } - gettimeofday(&fill_end, NULL); - gettimeofday(&fill_start, NULL); - pangulu_free(__FILE__, __LINE__, pt); - pangulu_free(__FILE__, __LINE__, block_nnz_pt); - pangulu_free(__FILE__, __LINE__, block_row_nnz_pt); - pangulu_free(__FILE__, __LINE__, block_row_pt); - pangulu_free(__FILE__, __LINE__, block_col_idx); - pangulu_free(__FILE__, __LINE__, bit_array); - pangulu_free(__FILE__, __LINE__, count_array); - pangulu_free(__FILE__, __LINE__, block_csr); - pangulu_free(__FILE__, __LINE__, every_rank_block_nnz); - pangulu_free(__FILE__, __LINE__, calculated_nzblk_count_each_rank); - pangulu_free(__FILE__, __LINE__, blkcsr_each_rank); - pangulu_free(__FILE__, __LINE__, sent_block_count_each_rank); - blkcsr_current_rank = (char *)pangulu_realloc(__FILE__, __LINE__, blkcsr_current_rank, sizeof(pangulu_exblock_ptr) * (block_length + 1) + (sizeof(pangulu_exblock_idx) + sizeof(pangulu_inblock_ptr)) * nzblk_current_rank); - - gettimeofday(&fill_end, NULL); - - gettimeofday(&fill_all_end, NULL); } - else - { - MPI_Status mpi_stat; - mpi_barrier_asym(MPI_COMM_WORLD, 0, 1e5); - MPI_Recv(&nzblk_current_rank, 1, MPI_PANGULU_EXBLOCK_PTR, 0, 0xCAFE + 1, MPI_COMM_WORLD, &mpi_stat); - MPI_Recv(&nnz_current_rank, 1, MPI_PANGULU_EXBLOCK_PTR, 0, 0xCAFE + 2, MPI_COMM_WORLD, &mpi_stat); - - blkcsr_current_rank = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (block_length + 1) + (sizeof(pangulu_exblock_idx) + sizeof(pangulu_inblock_ptr)) * nzblk_current_rank); - MPI_Recv(blkcsr_current_rank, sizeof(pangulu_exblock_ptr) * (block_length + 1) + (sizeof(pangulu_exblock_idx) + sizeof(pangulu_inblock_ptr)) * nzblk_current_rank, MPI_CHAR, 0, 0xCAFE + 3, MPI_COMM_WORLD, &mpi_stat); - blocks_current_rank = (char *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_ptr) * (nb + 1) * nzblk_current_rank + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * nnz_current_rank); + pangulu_free(__FILE__, __LINE__, bcsc_pointer); + pangulu_free(__FILE__, __LINE__, bcsc_index); + pangulu_free(__FILE__, __LINE__, bcsc_inblk_pointers); + pangulu_free(__FILE__, __LINE__, bcsc_inblk_indeces); + pangulu_free(__FILE__, __LINE__, bcsc_inblk_values); - pangulu_exblock_ptr *blkcsr_rowptr = (pangulu_exblock_ptr *)blkcsr_current_rank; - pangulu_exblock_idx *blkcsr_colidx = (pangulu_exblock_idx *)(blkcsr_current_rank + sizeof(pangulu_exblock_ptr) * (block_length + 1)); - pangulu_inblock_ptr *blkcsr_value_blknnz = (pangulu_inblock_ptr *)(blkcsr_current_rank + sizeof(pangulu_exblock_ptr) * (block_length + 1) + sizeof(pangulu_exblock_idx) * nzblk_current_rank); - - pangulu_int64_t blocks_current_rank_receive_offset = 0; - for (pangulu_exblock_idx brow = 0; brow < block_length; brow++) - { - for (pangulu_exblock_ptr bidx = blkcsr_rowptr[brow]; bidx < blkcsr_rowptr[brow + 1]; bidx++) - { - pangulu_exblock_idx bcol = blkcsr_colidx[bidx]; - MPI_Recv(blocks_current_rank + blocks_current_rank_receive_offset, sizeof(pangulu_inblock_ptr) * (nb + 1) + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * blkcsr_value_blknnz[bidx], MPI_CHAR, 0, bidx, MPI_COMM_WORLD, &mpi_stat); - - pangulu_smatrix *current = &Big_smatrix_value[current_rank_block_count]; - current->row = nb; - current->column = nb; - current->rowpointer = (pangulu_inblock_ptr *)(blocks_current_rank + blocks_current_rank_receive_offset); - current->nnz = current->rowpointer[nb]; - current->columnindex = (pangulu_inblock_idx *)(blocks_current_rank + blocks_current_rank_receive_offset + sizeof(pangulu_inblock_ptr) * (nb + 1)); - current->value = (calculate_type *)(blocks_current_rank + blocks_current_rank_receive_offset + sizeof(pangulu_inblock_ptr) * (nb + 1) + sizeof(pangulu_inblock_idx) * current->nnz); - - pangulu_bip_set(brow * block_length + bcol, BIP)->mapper_a = current_rank_block_count; - - blocks_current_rank_receive_offset += sizeof(pangulu_inblock_ptr) * (nb + 1) + (sizeof(pangulu_inblock_idx) + sizeof(calculate_type)) * blkcsr_value_blknnz[bidx]; - current_rank_block_count++; - } - } - } - pangulu_free(__FILE__, __LINE__, blkcsr_current_rank); for (pangulu_int64_t offset_block_index = 0; offset_block_index < p * q; offset_block_index++) { @@ -1020,7 +678,7 @@ void pangulu_preprocessing(pangulu_block_common *block_common, for (pangulu_int64_t i = 0; i < current_rank_block_count; i++) { - pangulu_smatrix_add_more_memory(&Big_smatrix_value[i]); + pangulu_smatrix_add_more_memory_csr(&Big_smatrix_value[i]); #ifdef GPU_OPEN pangulu_smatrix_add_cuda_memory(&Big_smatrix_value[i]); @@ -1530,8 +1188,11 @@ void pangulu_preprocessing(pangulu_block_common *block_common, } temp_a_value = (calculate_type *)pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nb * nb); + memset(temp_a_value, 0, sizeof(calculate_type) * nb * nb); ssssm_l_value = (calculate_type *)pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nb * nb); + memset(ssssm_l_value, 0, sizeof(calculate_type) * nb * nb); ssssm_u_value = (calculate_type *)pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nb * nb); + memset(ssssm_u_value, 0, sizeof(calculate_type) * nb * nb); ssssm_hash_l_row = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * (nb)); ssssm_hash_u_col = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * (nb)); ssssm_hash_lu = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * (nb)); @@ -1585,7 +1246,7 @@ void pangulu_preprocessing(pangulu_block_common *block_common, block_smatrix->save_send_rank_flag = save_send_rank_flag; block_smatrix->receive_level_num = receive_level_num; - block_smatrix->blocks_current_rank = blocks_current_rank; + // block_smatrix->blocks_current_rank = blocks_current_rank; block_smatrix->save_tmp = NULL; block_smatrix->level_index = level_index; diff --git a/src/pangulu_reorder.c b/src/pangulu_reorder.c index dd95bab..469f3ff 100644 --- a/src/pangulu_reorder.c +++ b/src/pangulu_reorder.c @@ -652,24 +652,24 @@ void pangulu_mc64(pangulu_origin_smatrix *s, pangulu_exblock_idx **perm, pangulu } #endif -void pangulu_origin_smatrix_transport_transport_iperm(pangulu_origin_smatrix *s, pangulu_origin_smatrix *new_S, pangulu_exblock_idx *metis_perm) +void pangulu_metis_reorder(pangulu_origin_smatrix *s, pangulu_origin_smatrix *new_S, pangulu_exblock_idx *metis_perm) { pangulu_exblock_idx n = s->row; pangulu_exblock_ptr nnz = s->nnz; pangulu_exblock_ptr *rowpointer = (pangulu_exblock_ptr *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); pangulu_exblock_idx *columnindex = (pangulu_exblock_idx *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * nnz); calculate_type *value = (calculate_type *)pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nnz); + #pragma omp parallel for for (pangulu_exblock_idx i = 0; i < n; i++) { - pangulu_exblock_idx row_num = s->rowpointer[i + 1] - s->rowpointer[i]; - pangulu_exblock_idx index = metis_perm[i]; - rowpointer[index + 1] = row_num; + rowpointer[metis_perm[i] + 1] = s->rowpointer[i + 1] - s->rowpointer[i]; } rowpointer[0] = 0; for (pangulu_exblock_idx i = 0; i < n; i++) { rowpointer[i + 1] += rowpointer[i]; } + #pragma omp parallel for for (pangulu_exblock_idx i = 0; i < n; i++) { pangulu_exblock_idx index = metis_perm[i]; @@ -689,185 +689,105 @@ void pangulu_origin_smatrix_transport_transport_iperm(pangulu_origin_smatrix *s, } #ifdef METIS -void pangulu_get_graph_struct(pangulu_origin_smatrix *s, idx_t **xadj_adress, idx_t **adjincy_adress) -{ + +void pangulu_get_graph_struct(pangulu_origin_smatrix *s, idx_t **xadj_address, idx_t **adjincy_address){ + struct timeval start_time; + + pangulu_time_start(&start_time); pangulu_add_diagonal_element(s); + printf("[PanguLU Info] 2.1 PanguLU METIS add_diagonal_element time is %lf s.\n", pangulu_time_stop(&start_time)); + + pangulu_time_start(&start_time); pangulu_origin_smatrix_add_csc(s); + printf("[PanguLU Info] 2.2 PanguLU METIS transpose time is %lf s.\n", pangulu_time_stop(&start_time)); + + pangulu_time_start(&start_time); idx_t *xadj = (idx_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(idx_t) * (s->row + 1)); - xadj[0] = 0; + idx_t *adjincy = pangulu_malloc(__FILE__, __LINE__, sizeof(idx_t) * s->nnz * 2); - for (pangulu_exblock_idx i = 0; i < s->row; i++) - { - pangulu_exblock_ptr index1 = s->rowpointer[i]; - pangulu_exblock_ptr index2 = s->columnpointer[i]; - pangulu_exblock_ptr end1 = s->rowpointer[i + 1]; - pangulu_exblock_ptr end2 = s->columnpointer[i + 1]; - char diagonal_flag = 0; - pangulu_int64_t sum_num = 0; - pangulu_exblock_idx col1 = s->columnindex[index1]; - pangulu_exblock_idx col2 = s->rowindex[index2]; - while ((index1 < end1) && (index2 < end2)) - { - if (col1 == col2) - { - if ((diagonal_flag == 0) && (col1 == i)) - { - diagonal_flag = 1; + xadj[0] = 0; + for(pangulu_exblock_idx rc = 0; rc < s->row; rc++){ + pangulu_exblock_idx nnz_count = 0; + pangulu_exblock_ptr start1 = s->rowpointer[rc]; + pangulu_exblock_ptr end1 = s->rowpointer[rc+1]; + pangulu_exblock_ptr start2 = s->columnpointer[rc]; + pangulu_exblock_ptr end2 = s->columnpointer[rc+1]; + pangulu_exblock_ptr idx1 = start1; + pangulu_exblock_ptr idx2 = start2; + + while((idx1 < end1) && (idx2 < end2)){ + if(s->columnindex[idx1] < s->rowindex[idx2]){ + idx1++; + }else if(s->columnindex[idx1] > s->rowindex[idx2]){ + idx2++; + }else{ + idx1++; + idx2++; + } + nnz_count++; + } + while(idx1 < end1){ + idx1++; + nnz_count++; + } + while(idx2 < end2){ + idx2++; + nnz_count++; + } + nnz_count--; + xadj[rc + 1] = xadj[rc] + nnz_count; + + nnz_count = 0; + idx1 = start1; + idx2 = start2; + while((idx1 < end1) && (idx2 < end2)){ + if(s->columnindex[idx1] < s->rowindex[idx2]){ + if(s->columnindex[idx1] != rc){ + adjincy[xadj[rc] + nnz_count] = s->columnindex[idx1]; + nnz_count++; } - index1++; - index2++; - col1 = s->columnindex[index1]; - col2 = s->rowindex[index2]; - } - else if (col1 < col2) - { - if ((diagonal_flag == 0) && (col1 == i)) - { - diagonal_flag = 1; + idx1++; + }else if(s->columnindex[idx1] > s->rowindex[idx2]){ + if(s->rowindex[idx2] != rc){ + adjincy[xadj[rc] + nnz_count] = s->rowindex[idx2]; + nnz_count++; } - index1++; - col1 = s->columnindex[index1]; - } - else - { - if ((diagonal_flag == 0) && (col2 == i)) - { - diagonal_flag = 1; + idx2++; + }else{ + if(s->columnindex[idx1] != rc){ + adjincy[xadj[rc] + nnz_count] = s->columnindex[idx1]; + nnz_count++; } - index2++; - col2 = s->rowindex[index2]; + idx1++; + idx2++; } - sum_num++; } - while (index1 < end1) - { - sum_num++; - if ((diagonal_flag == 0) && (col1 == i)) - { - diagonal_flag = 1; + while(idx1 < end1){ + if(s->columnindex[idx1] != rc){ + adjincy[xadj[rc] + nnz_count] = s->columnindex[idx1]; + nnz_count++; } - index1++; - col1 = s->columnindex[index1]; + idx1++; } - - while (index2 < end2) - { - sum_num++; - if ((diagonal_flag == 0) && (col2 == i)) - { - diagonal_flag = 1; + while(idx2 < end2){ + if(s->rowindex[idx2] != rc){ + adjincy[xadj[rc] + nnz_count] = s->rowindex[idx2]; + nnz_count++; } - index2++; - col2 = s->rowindex[index2]; + idx2++; } - if (diagonal_flag == 0) - { - printf(PANGULU_E_ROW_DONT_HAVE_DIA); - pangulu_exit(1); - } - xadj[i + 1] = sum_num - diagonal_flag; - } - for (pangulu_exblock_idx i = 0; i < s->row; i++) - { - xadj[i + 1] += xadj[i]; } - idx_t *adjincy = (idx_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(idx_t) * (xadj[s->row])); - - for (pangulu_exblock_ptr i = 0; i < s->row; i++) - { - idx_t now_adjincy_index = xadj[i]; - pangulu_exblock_ptr index1 = s->rowpointer[i]; - pangulu_exblock_ptr index2 = s->columnpointer[i]; - pangulu_exblock_ptr end1 = s->rowpointer[i + 1]; - pangulu_exblock_ptr end2 = s->columnpointer[i + 1]; - char diagonal_flag = 0; - pangulu_exblock_idx col1 = s->columnindex[index1]; - pangulu_exblock_idx col2 = s->rowindex[index2]; - while ((index1 < end1) && (index2 < end2)) - { - if (col1 == col2) - { - if ((diagonal_flag == 0) && (col1 == i)) - { - diagonal_flag = 1; - } - else - { - adjincy[now_adjincy_index] = col1; - now_adjincy_index++; - } - index1++; - index2++; - col1 = s->columnindex[index1]; - col2 = s->rowindex[index2]; - } - else if (col1 < col2) - { - if ((diagonal_flag == 0) && (col1 == i)) - { - diagonal_flag = 1; - } - else - { - adjincy[now_adjincy_index] = col1; - now_adjincy_index++; - } - index1++; - col1 = s->columnindex[index1]; - } - else - { - if ((diagonal_flag == 0) && (col2 == i)) - { - diagonal_flag = 1; - } - else - { - adjincy[now_adjincy_index] = col2; - now_adjincy_index++; - } - index2++; - col2 = s->rowindex[index2]; - } - } - while (index1 < end1) - { - if ((diagonal_flag == 0) && (col1 == i)) - { - diagonal_flag = 1; - } - else - { - adjincy[now_adjincy_index] = col1; - now_adjincy_index++; - } - index1++; - col1 = s->columnindex[index1]; - } - - while (index2 < end2) - { - if ((diagonal_flag == 0) && (col2 == i)) - { - diagonal_flag = 1; - } - else - { - adjincy[now_adjincy_index] = col2; - now_adjincy_index++; - } - index2++; - col2 = s->rowindex[index2]; - } - } - *xadj_adress = xadj; - *adjincy_adress = adjincy; + adjincy = pangulu_realloc(__FILE__, __LINE__, adjincy, sizeof(idx_t) * xadj[s->row]); + *xadj_address = xadj; + *adjincy_address = adjincy; + printf("[PanguLU Info] 2.3 PanguLU METIS get_graph_struct.other_code time is %lf s.\n", pangulu_time_stop(&start_time)); } void pangulu_metis(pangulu_origin_smatrix *a, idx_t **metis_perm) { + struct timeval start_time; idx_t n = a->row; idx_t *iperm = (idx_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(idx_t) * n); @@ -876,8 +796,13 @@ void pangulu_metis(pangulu_origin_smatrix *a, idx_t **metis_perm) idx_t *xadj = NULL; idx_t *adjincy = NULL; + pangulu_time_start(&start_time); pangulu_get_graph_struct(a, &xadj, &adjincy); + printf("[PanguLU Info] 2 PanguLU METIS get_graph_struct time is %lf s.\n", pangulu_time_stop(&start_time)); + + pangulu_time_start(&start_time); METIS_NodeND(&n, xadj, adjincy, NULL, NULL, perm, iperm); + printf("[PanguLU Info] 3.1 PanguLU METIS generate the perm time is %lf s.\n", pangulu_time_stop(&start_time)); pangulu_free(__FILE__, __LINE__, perm); pangulu_free(__FILE__, __LINE__, xadj); @@ -930,6 +855,7 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, pangulu_origin_smatrix *origin_matrix, pangulu_origin_smatrix *reorder_matrix) { + struct timeval start_time; pangulu_exblock_idx n = origin_matrix->row; pangulu_exblock_ptr nnz = origin_matrix->nnz; pangulu_exblock_idx *perm = NULL; @@ -942,7 +868,9 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, if (rank == 0) { #if defined(PANGULU_MC64) + pangulu_time_start(&start_time); pangulu_mc64(origin_matrix, &perm, &iperm, &row_scale, &col_scale); + printf("[PanguLU Info] 1.1 PanguLU MC64 generate the perm time is %lf s.\n", pangulu_time_stop(&start_time)); #else perm = (pangulu_exblock_idx *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * n); iperm = (pangulu_exblock_idx *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * n); @@ -970,6 +898,7 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, col_scale[i] = 1.0; } #endif + pangulu_time_start(&start_time); tmp = (pangulu_origin_smatrix *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_origin_smatrix)); pangulu_init_pangulu_origin_smatrix(tmp); tmp->row = n; @@ -981,6 +910,7 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, tmp->rowpointer[0] = 0; + #pragma omp parallel for for (pangulu_int64_t i = 0; i < n; i++) { pangulu_int64_t row = perm[i]; @@ -992,6 +922,7 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, tmp->rowpointer[i + 1] += tmp->rowpointer[i]; } + #pragma omp parallel for for (pangulu_int64_t i = 0; i < n; i++) { pangulu_exblock_idx row = perm[i]; @@ -1002,15 +933,10 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, pangulu_exblock_idx col = origin_matrix->columnindex[j]; tmp->columnindex[tmp_index] = col; tmp->value[tmp_index] = (origin_matrix->value[j] * rs * col_scale[col]); - // if (col == row) - // { - // if (fabs(fabs(tmp->value[tmp_index]) - 1.0) > 1e-10) - // { - // } - // } tmp_index++; } } + printf("[PanguLU Info] 1.2 PanguLU MC64 reordering time is %lf s.\n", pangulu_time_stop(&start_time)); } #ifdef METIS @@ -1037,8 +963,17 @@ void pangulu_reorder(pangulu_block_smatrix *block_smatrix, #endif if (rank == 0) { - pangulu_origin_smatrix_transport_transport_iperm(tmp, reorder_matrix, metis_perm); + pangulu_time_start(&start_time); + pangulu_metis_reorder(tmp, reorder_matrix, metis_perm); pangulu_sort_pangulu_origin_smatrix(reorder_matrix); + for(pangulu_exblock_idx row = 0; row < n; row++){ + for(pangulu_exblock_ptr idx = reorder_matrix->rowpointer[row]; idx < reorder_matrix->rowpointer[row+1]; idx++){ + if((row == reorder_matrix->columnindex[idx]) && (fabs(reorder_matrix->value[idx]) < ZERO_ELEMENT)){ + reorder_matrix->value[idx] = ZERO_ELEMENT; + } + } + } + printf("[PanguLU Info] 3.2 PanguLU METIS reordering time is %lf s.\n", pangulu_time_stop(&start_time)); block_smatrix->row_perm = perm; block_smatrix->col_perm = iperm; diff --git a/src/pangulu_symbolic.c b/src/pangulu_symbolic.c index a789a59..5e3cb33 100644 --- a/src/pangulu_symbolic.c +++ b/src/pangulu_symbolic.c @@ -507,9 +507,12 @@ void pangulu_symbolic(pangulu_block_common *block_common, pangulu_exblock_ptr *new_rowpointer=NULL; pangulu_exblock_idx *new_columnindex=NULL; pangulu_exblock_ptr new_nnz; + struct timeval start_time; + pangulu_time_start(&start_time); at_plus_a_dist(reorder_matrix->row,reorder_matrix->nnz, reorder_matrix->rowpointer,reorder_matrix->columnindex, &new_nnz,&new_rowpointer,&new_columnindex); + printf("[PanguLU Info] 4 PanguLU A+AT (before symbolic) time is %lf s.\n", pangulu_time_stop(&start_time)); pangulu_exblock_ptr *symbolic_rowpointer = NULL; pangulu_exblock_idx *symbolic_columnindex = NULL; pangulu_inblock_idx nb = block_common->nb; @@ -532,6 +535,7 @@ void pangulu_symbolic(pangulu_block_common *block_common, block_smatrix_nnzA_num[i] = 0; } + pangulu_time_start(&start_time); fill_in_sym_prune(reorder_matrix->row,new_nnz,new_columnindex,new_rowpointer, &symbolic_rowpointer,&symbolic_columnindex, nb,block_length, @@ -540,6 +544,7 @@ void pangulu_symbolic(pangulu_block_common *block_common, block_smatrix_nnzA_num, &block_smatrix->symbolic_nnz ); + printf("[PanguLU Info] 5 PanguLU symbolic time is %lf s.\n", pangulu_time_stop(&start_time)); pangulu_free(__FILE__, __LINE__, new_rowpointer); pangulu_free(__FILE__, __LINE__, new_columnindex); diff --git a/src/pangulu_time.c b/src/pangulu_time.c index 700c4d3..3404d20 100644 --- a/src/pangulu_time.c +++ b/src/pangulu_time.c @@ -15,7 +15,7 @@ double pangulu_time_check_end(struct timeval *GET_TIME_START) void pangulu_time_init() { - time_transport = 0.0; + time_transpose = 0.0; time_isend = 0.0; time_receive = 0.0; time_getrf = 0.0; diff --git a/src/pangulu_tstrf_fp64.c b/src/pangulu_tstrf_fp64.c index 3f0e11d..8c3fd75 100644 --- a/src/pangulu_tstrf_fp64.c +++ b/src/pangulu_tstrf_fp64.c @@ -351,10 +351,10 @@ void pangulu_tstrf_interface_c_v1(pangulu_smatrix *a, #ifdef GPU_OPEN pangulu_smatrix_cuda_memcpy_value_csc(a, a); #endif - pangulu_transport_pangulu_smatrix_csc_to_csr(a); + pangulu_transpose_pangulu_smatrix_csc_to_csr(a); pangulu_pangulu_smatrix_memcpy_value_csc_copy_length(x, a); pangulu_tstrf_fp64_cpu_4(a, x, u); - pangulu_transport_pangulu_smatrix_csr_to_csc(a); + pangulu_transpose_pangulu_smatrix_csr_to_csc(a); #ifdef GPU_OPEN pangulu_smatrix_cuda_memcpy_to_device_value_csc(a, a); #endif @@ -366,10 +366,10 @@ void pangulu_tstrf_interface_c_v2(pangulu_smatrix *a, #ifdef GPU_OPEN pangulu_smatrix_cuda_memcpy_value_csc(a, a); #endif - pangulu_transport_pangulu_smatrix_csc_to_csr(a); + pangulu_transpose_pangulu_smatrix_csc_to_csr(a); pangulu_pangulu_smatrix_memcpy_value_csc_copy_length(x, a); pangulu_tstrf_fp64_cpu_6(a, x, u); - pangulu_transport_pangulu_smatrix_csr_to_csc(a); + pangulu_transpose_pangulu_smatrix_csr_to_csc(a); #ifdef GPU_OPEN pangulu_smatrix_cuda_memcpy_to_device_value_csc(a, a); #endif diff --git a/src/pangulu_tstrf_fp64_cuda.c b/src/pangulu_tstrf_fp64_cuda.c index 01145a5..01d3546 100644 --- a/src/pangulu_tstrf_fp64_cuda.c +++ b/src/pangulu_tstrf_fp64_cuda.c @@ -178,11 +178,11 @@ void pangulu_tstrf_interface_G_V1(pangulu_smatrix *a, pangulu_smatrix *u) { pangulu_smatrix_cuda_memcpy_value_csc(a, a); - pangulu_transport_pangulu_smatrix_csc_to_csr(a); + pangulu_transpose_pangulu_smatrix_csc_to_csr(a); pangulu_smatrix_cuda_memcpy_complete_csr(a, a); pangulu_tstrf_fp64_cuda_v7(a, x, u); pangulu_smatrix_cuda_memcpy_value_csr(a, x); - pangulu_transport_pangulu_smatrix_csr_to_csc(a); + pangulu_transpose_pangulu_smatrix_csr_to_csc(a); } void pangulu_tstrf_interface_G_V2(pangulu_smatrix *a, pangulu_smatrix *x, @@ -196,10 +196,10 @@ void pangulu_tstrf_interface_G_V3(pangulu_smatrix *a, pangulu_smatrix *u) { pangulu_smatrix_cuda_memcpy_value_csc(a, a); - pangulu_transport_pangulu_smatrix_csc_to_csr(a); + pangulu_transpose_pangulu_smatrix_csc_to_csr(a); pangulu_smatrix_cuda_memcpy_complete_csr(a, a); pangulu_tstrf_fp64_cuda_v10(a, x, u); pangulu_smatrix_cuda_memcpy_value_csr(a, x); - pangulu_transport_pangulu_smatrix_csr_to_csc(a); + pangulu_transpose_pangulu_smatrix_csr_to_csc(a); } #endif \ No newline at end of file diff --git a/src/pangulu_utils.c b/src/pangulu_utils.c index f66e74d..e199a64 100644 --- a/src/pangulu_utils.c +++ b/src/pangulu_utils.c @@ -1,5 +1,1136 @@ #include "pangulu_common.h" +void pangulu_sort_exblock_struct( + pangulu_exblock_idx n, + pangulu_exblock_ptr* pointer, + pangulu_exblock_idx* index, + pangulu_int32_t nthread +){ + if(nthread <= 0){ + nthread = sysconf(_SC_NPROCESSORS_ONLN); + } + + #pragma omp parallel num_threads(nthread) + { + bind_to_core(omp_get_thread_num() % sysconf(_SC_NPROCESSORS_ONLN)); + } + + #pragma omp parallel for num_threads(nthread) schedule(guided) + for (pangulu_exblock_idx i = 0; i < n; i++) + { + pangulu_kvsort(index, NULL, pointer[i], pointer[i + 1] - 1); + } +} + +int cmp_exidx_asc(const void* a, const void* b){ + if((*(pangulu_exblock_idx*)a) > (*(pangulu_exblock_idx*)b)){ + return 1; + }else if((*(pangulu_exblock_idx*)a) < (*(pangulu_exblock_idx*)b)){ + return -1; + }else{ + return 0; + } +} + + +void pangulu_kvsort(pangulu_exblock_idx *key, calculate_type *val, pangulu_int64_t start, pangulu_int64_t end) +{ + if(val){ + if (start < end) + { + pangulu_int64_t pivot; + pangulu_int64_t i, j, k; + + // k = choose_pivot(start, end); + k = (start + end) / 2; + swap_index_1(&key[start], &key[k]); + swap_value(&val[start], &val[k]); + pivot = key[start]; + + i = start + 1; + j = end; + while (i <= j) + { + while ((i <= end) && (key[i] <= pivot)) + i++; + while ((j >= start) && (key[j] > pivot)) + j--; + if (i < j) + { + swap_index_1(&key[i], &key[j]); + swap_value(&val[i], &val[j]); + } + } + + // swap two elements + swap_index_1(&key[start], &key[j]); + swap_value(&val[start], &val[j]); + + // recursively sort the lesser key + pangulu_kvsort(key, val, start, j - 1); + pangulu_kvsort(key, val, j + 1, end); + } + }else{ + qsort(key + start, end + 1 - start , sizeof(pangulu_exblock_idx), cmp_exidx_asc); + } +} + +void pangulu_cm_distribute_distcsc_to_distbcsc( + int rootproc_free_originmatrix, + int malloc_distbcsc_value, + pangulu_exblock_idx n_glo, + pangulu_exblock_idx n_loc, + pangulu_inblock_idx block_order, + + pangulu_exblock_ptr* distcsc_proc_nnzptr, + pangulu_exblock_ptr* distcsc_pointer, + pangulu_exblock_idx* distcsc_index, + calculate_type* distcsc_value, + + pangulu_exblock_ptr** bcsc_struct_pointer, + pangulu_exblock_idx** bcsc_struct_index, + pangulu_exblock_ptr** bcsc_struct_nnzptr, + pangulu_inblock_ptr*** bcsc_inblock_pointers, + pangulu_inblock_idx*** bcsc_inblock_indeces, + calculate_type*** bcsc_values +){ +#define _PANGULU_SET_VALUE_SIZE(size) ((distcsc_value)?(size):(0)) +#define _PANGULU_SET_BVALUE_SIZE(size) ((malloc_distbcsc_value)?(size):(0)) + + if(distcsc_value){ + malloc_distbcsc_value = 1; + } + // printf("malloc_distbcsc_value = %d\n", malloc_distbcsc_value); + + struct timeval start_time; + pangulu_time_start(&start_time); + + pangulu_int32_t rank, nproc; + pangulu_cm_rank(&rank); + pangulu_cm_size(&nproc); + + if(distcsc_proc_nnzptr){ + pangulu_free(__FILE__, __LINE__, distcsc_proc_nnzptr); + } + // printf("1.1\n"); + + int preprocess_ompnum_separate_block = 2; + + bind_to_core((rank * preprocess_ompnum_separate_block) % sysconf(_SC_NPROCESSORS_ONLN)); + + #pragma omp parallel num_threads(preprocess_ompnum_separate_block) + { + bind_to_core((rank * preprocess_ompnum_separate_block + omp_get_thread_num()) % sysconf(_SC_NPROCESSORS_ONLN)); + } + + pangulu_int64_t p = sqrt(nproc); + while ((nproc % p) != 0) + { + p--; + } + pangulu_int64_t q = nproc / p; + pangulu_exblock_idx col_per_rank = PANGULU_ICEIL(PANGULU_ICEIL(n_glo, block_order * q), nproc) * (block_order * q); + pangulu_int64_t block_length = PANGULU_ICEIL(col_per_rank, block_order); + pangulu_int64_t block_length_col = PANGULU_ICEIL(n_glo, block_order); + pangulu_exblock_ptr nnz = distcsc_pointer[n_loc]; + pangulu_int64_t bit_length = (block_length_col + 31) / 32; + pangulu_int64_t block_num = 0; + pangulu_int64_t *block_nnz_pt; + // printf("1.2\n"); + + pangulu_int64_t avg_nnz = PANGULU_ICEIL(nnz, preprocess_ompnum_separate_block); + pangulu_int64_t *block_row_nnz_pt = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * (block_length + 1)); + for (int i = 0; i < block_length; i++) + { + block_row_nnz_pt[i] = distcsc_pointer[PANGULU_MIN(i * block_order, n_loc)]; + } + block_row_nnz_pt[block_length] = distcsc_pointer[n_loc]; + + int *thread_pt = (int *)pangulu_malloc(__FILE__, __LINE__, sizeof(int) * (preprocess_ompnum_separate_block + 1)); + thread_pt[0] = 0; + for (int i = 1; i < preprocess_ompnum_separate_block + 1; i++) + { + thread_pt[i] = binarylowerbound(block_row_nnz_pt, block_length, avg_nnz * i); + } + pangulu_free(__FILE__, __LINE__, block_row_nnz_pt); + block_row_nnz_pt = NULL; + + pangulu_int64_t *block_row_pt = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * (block_length + 1)); + memset(block_row_pt, 0, sizeof(pangulu_int64_t) * (block_length + 1)); + + unsigned int *bit_array = (unsigned int *)pangulu_malloc(__FILE__, __LINE__, sizeof(unsigned int) * bit_length * preprocess_ompnum_separate_block); + +#pragma omp parallel num_threads(preprocess_ompnum_separate_block) + { + int tid = omp_get_thread_num(); + unsigned int *tmp_bit = bit_array + bit_length * tid; + + for (int level = thread_pt[tid]; level < thread_pt[tid + 1]; level++) + { + memset(tmp_bit, 0, sizeof(unsigned int) * bit_length); + + int start_row = level * block_order; + int end_row = ((level + 1) * block_order) < n_loc ? ((level + 1) * block_order) : n_loc; + + for (int rid = start_row; rid < end_row; rid++) + { + for (pangulu_int64_t idx = distcsc_pointer[rid]; idx < distcsc_pointer[rid + 1]; idx++) + { + pangulu_int32_t colidx = distcsc_index[idx]; + pangulu_int32_t block_cid = colidx / block_order; + setbit(tmp_bit[block_cid / 32], block_cid % 32); + } + } + + pangulu_int64_t tmp_blocknum = 0; + for (int i = 0; i < bit_length; i++) + { + tmp_blocknum += __builtin_popcount(tmp_bit[i]); + } + + block_row_pt[level] = tmp_blocknum; + } + } + exclusive_scan_1(block_row_pt, block_length + 1); + block_num = block_row_pt[block_length]; + + block_nnz_pt = (pangulu_int64_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int64_t) * (block_num + 1)); + memset(block_nnz_pt, 0, sizeof(pangulu_int64_t) * (block_num + 1)); + pangulu_int32_t *block_col_idx = (pangulu_int32_t *)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_int32_t) * block_num); + + int *count_array = (int *)pangulu_malloc(__FILE__, __LINE__, sizeof(int) * block_length_col * preprocess_ompnum_separate_block); +#pragma omp parallel num_threads(preprocess_ompnum_separate_block) + { + int tid = omp_get_thread_num(); + unsigned int *tmp_bit = bit_array + bit_length * tid; + int *tmp_count = count_array + block_length_col * tid; + + for (int level = thread_pt[tid]; level < thread_pt[tid + 1]; level++) + { + memset(tmp_bit, 0, sizeof(unsigned int) * bit_length); + memset(tmp_count, 0, sizeof(int) * block_length_col); + + pangulu_int64_t *cur_block_nnz_pt = block_nnz_pt + block_row_pt[level]; + pangulu_int32_t *cur_block_col_idx = block_col_idx + block_row_pt[level]; + + int start_row = level * block_order; + int end_row = ((level + 1) * block_order) < n_loc ? ((level + 1) * block_order) : n_loc; + + for (int rid = start_row; rid < end_row; rid++) + { + for (pangulu_int64_t idx = distcsc_pointer[rid]; idx < distcsc_pointer[rid + 1]; idx++) + { + pangulu_int32_t colidx = distcsc_index[idx]; + pangulu_int32_t block_cid = colidx / block_order; + setbit(tmp_bit[block_cid / 32], block_cid % 32); + tmp_count[block_cid]++; + } + } + + pangulu_int64_t cnt = 0; + for (int i = 0; i < block_length_col; i++) + { + if (getbit(tmp_bit[i / 32], i % 32)) + { + cur_block_nnz_pt[cnt] = tmp_count[i]; + cur_block_col_idx[cnt] = i; + cnt++; + } + } + } + } + pangulu_free(__FILE__, __LINE__, bit_array); + bit_array = NULL; + pangulu_free(__FILE__, __LINE__, count_array); + count_array = NULL; + exclusive_scan_1(block_nnz_pt, block_num + 1); + + // printf("1.3\n"); + + pangulu_exblock_ptr* nzblk_each_rank_ptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (nproc + 1)); + pangulu_exblock_ptr* nnz_each_rank_ptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (nproc + 1)); + memset(nzblk_each_rank_ptr, 0, sizeof(pangulu_exblock_ptr) * (nproc + 1)); + memset(nnz_each_rank_ptr, 0, sizeof(pangulu_exblock_ptr) * (nproc + 1)); + for(pangulu_exblock_idx bcol = 0; bcol < block_length; bcol++){ + for(pangulu_exblock_ptr bidx = block_row_pt[bcol]; bidx < block_row_pt[bcol+1]; bidx++){ + pangulu_exblock_idx brow = block_col_idx[bidx]; + nzblk_each_rank_ptr[(brow % p) * q + (bcol % q) + 1]++; + nnz_each_rank_ptr[(brow % p) * q + (bcol % q) + 1] += (block_nnz_pt[bidx + 1] - block_nnz_pt[bidx]); + } + } + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + nzblk_each_rank_ptr[remote_rank + 1] += nzblk_each_rank_ptr[remote_rank]; + nnz_each_rank_ptr[remote_rank + 1] += nnz_each_rank_ptr[remote_rank]; + } + char** csc_draft_remote = pangulu_malloc(__FILE__, __LINE__, sizeof(char*) * nproc); + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + csc_draft_remote[remote_rank] = pangulu_malloc( + __FILE__, __LINE__, + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank]) + + sizeof(pangulu_exblock_ptr) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank] + 1) + ); + memset(csc_draft_remote[remote_rank], 0, + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank]) + + sizeof(pangulu_exblock_ptr) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank] + 1) + ); + } + + for(pangulu_exblock_idx bcol = 0; bcol < block_length; bcol++){ + for(pangulu_exblock_ptr bidx = block_row_pt[bcol]; bidx < block_row_pt[bcol+1]; bidx++){ + pangulu_exblock_idx brow = block_col_idx[bidx]; + pangulu_inblock_ptr nnz_in_blk = block_nnz_pt[bidx + 1] - block_nnz_pt[bidx]; + pangulu_int32_t remote_rank = (brow % p) * q + (bcol % q); + pangulu_exblock_ptr* remote_bcolptr = (pangulu_exblock_ptr*)csc_draft_remote[remote_rank]; + remote_bcolptr[bcol + 1]++; + } + } + // printf("1.4\n"); + + pangulu_exblock_ptr* aid_arr_colptr_remote = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (block_length + 1) * nproc); + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + pangulu_exblock_ptr* remote_bcolptr = (pangulu_exblock_ptr*)csc_draft_remote[remote_rank]; + for(pangulu_exblock_idx bcol = 0; bcol < block_length; bcol++){ + remote_bcolptr[bcol + 1] += remote_bcolptr[bcol]; + } + memcpy(&aid_arr_colptr_remote[(block_length + 1) * remote_rank], remote_bcolptr, sizeof(pangulu_exblock_ptr) * (block_length + 1)); + } + + for(pangulu_exblock_idx bcol = 0; bcol < block_length; bcol++){ + for(pangulu_exblock_ptr bidx = block_row_pt[bcol]; bidx < block_row_pt[bcol+1]; bidx++){ + pangulu_exblock_idx brow = block_col_idx[bidx]; + pangulu_inblock_ptr nnz_in_blk = block_nnz_pt[bidx + 1] - block_nnz_pt[bidx]; + pangulu_int32_t remote_rank = (brow % p) * q + (bcol % q); + + pangulu_exblock_idx* remote_browidx = (pangulu_exblock_idx*) + (csc_draft_remote[remote_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1)); + pangulu_exblock_ptr* remote_blknnzptr = (pangulu_exblock_ptr*) + (csc_draft_remote[remote_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank])); + + remote_browidx[aid_arr_colptr_remote[(block_length + 1) * remote_rank + bcol]] = brow; + remote_blknnzptr[aid_arr_colptr_remote[(block_length + 1) * remote_rank + bcol] + 1] = nnz_in_blk; + aid_arr_colptr_remote[(block_length + 1) * remote_rank + bcol]++; + } + } + pangulu_free(__FILE__, __LINE__, aid_arr_colptr_remote); + aid_arr_colptr_remote = NULL; + pangulu_free(__FILE__, __LINE__, block_nnz_pt); + block_nnz_pt = NULL; + + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + pangulu_exblock_ptr* remote_bcolptr = csc_draft_remote[remote_rank]; + pangulu_exblock_ptr* remote_blknnzptr = + csc_draft_remote[remote_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank]); + for(pangulu_inblock_ptr bidx = 0; bidx < remote_bcolptr[block_length]; bidx++){ + remote_blknnzptr[bidx + 1] += remote_blknnzptr[bidx]; + } + } + + char** block_csc_remote = pangulu_malloc(__FILE__, __LINE__, sizeof(char*) * nproc); + for(pangulu_int32_t target_rank = 0; target_rank < nproc; target_rank++){ + block_csc_remote[target_rank] = pangulu_malloc( + __FILE__, __LINE__, + sizeof(pangulu_inblock_ptr) * (block_order + 1) * (nzblk_each_rank_ptr[target_rank + 1] - nzblk_each_rank_ptr[target_rank]) + + sizeof(pangulu_inblock_idx) * (nnz_each_rank_ptr[target_rank + 1] - nnz_each_rank_ptr[target_rank]) + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * (nnz_each_rank_ptr[target_rank + 1] - nnz_each_rank_ptr[target_rank]) + ); + memset( + block_csc_remote[target_rank], 0, + sizeof(pangulu_inblock_ptr) * (block_order + 1) * (nzblk_each_rank_ptr[target_rank + 1] - nzblk_each_rank_ptr[target_rank]) + + sizeof(pangulu_inblock_idx) * (nnz_each_rank_ptr[target_rank + 1] - nnz_each_rank_ptr[target_rank]) + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * (nnz_each_rank_ptr[target_rank + 1] - nnz_each_rank_ptr[target_rank]) + ); + } + + +#pragma omp parallel num_threads(preprocess_ompnum_separate_block) + { + int tid = omp_get_thread_num(); + int* tmp_count = pangulu_malloc(__FILE__, __LINE__, sizeof(int) * block_length_col * q); + + for (int level = thread_pt[tid]; level < thread_pt[tid + 1]; level++) + { + + memset(tmp_count, 0, sizeof(int) * block_length_col * q); + + pangulu_exblock_idx start_col = level * block_order; + pangulu_exblock_idx end_col = ((level + 1) * block_order) < n_loc ? ((level + 1) * block_order) : n_loc; + + for (pangulu_exblock_idx col = start_col, col_in_blc = 0; col < end_col; col++, col_in_blc++) + { + pangulu_int64_t bidx_glo = block_row_pt[level]; + pangulu_exblock_idx brow = block_col_idx[bidx_glo]; + pangulu_int32_t target_rank = (brow % p) * q + (level % q); + pangulu_exblock_ptr* remote_bcolptr = csc_draft_remote[target_rank]; + pangulu_exblock_idx* remote_browidx = csc_draft_remote[target_rank] + sizeof(pangulu_exblock_ptr) * (block_length + 1); + pangulu_exblock_ptr* remote_bnnzptr = + csc_draft_remote[target_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[target_rank + 1] - nzblk_each_rank_ptr[target_rank]); + pangulu_int64_t bidx = remote_bcolptr[level]; + + pangulu_int64_t arr_len = + sizeof(pangulu_inblock_ptr) * bidx * (block_order + 1) + + (sizeof(pangulu_inblock_idx) + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type))) * remote_bnnzptr[bidx]; + pangulu_inblock_ptr *cur_block_rowptr = (pangulu_inblock_ptr *)(block_csc_remote[target_rank] + arr_len); + pangulu_inblock_idx *cur_block_colidx = (pangulu_inblock_idx *)(block_csc_remote[target_rank] + arr_len + sizeof(pangulu_inblock_ptr) * (block_order + 1)); + calculate_type *cur_block_value = NULL; + if(malloc_distbcsc_value){ + cur_block_value = (calculate_type *)( + block_csc_remote[target_rank] + arr_len + + sizeof(pangulu_inblock_ptr) * (block_order + 1) + + sizeof(pangulu_inblock_idx) * (remote_bnnzptr[bidx + 1] - remote_bnnzptr[bidx]) + ); + } + + pangulu_exblock_ptr reorder_matrix_idx = distcsc_pointer[col]; + pangulu_exblock_ptr reorder_matrix_idx_ub = distcsc_pointer[col + 1]; + for (pangulu_exblock_ptr idx = distcsc_pointer[col]; idx < distcsc_pointer[col + 1]; idx++) + { + pangulu_exblock_idx row = distcsc_index[idx]; + brow = row / block_order; + if (block_col_idx[bidx_glo] != brow) + { + bidx_glo = binarysearch(block_col_idx, bidx_glo, block_row_pt[level + 1], brow); + target_rank = (brow % p) * q + (level % q); + remote_bcolptr = csc_draft_remote[target_rank]; + remote_browidx = csc_draft_remote[target_rank] + sizeof(pangulu_exblock_ptr) * (block_length + 1); + remote_bnnzptr = + csc_draft_remote[target_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[target_rank + 1] - nzblk_each_rank_ptr[target_rank]); + bidx = binarysearch(remote_browidx, remote_bcolptr[level], remote_bcolptr[level + 1], brow); + arr_len = + sizeof(pangulu_inblock_ptr) * bidx * (block_order + 1) + + (sizeof(pangulu_inblock_idx) + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type))) * remote_bnnzptr[bidx]; + cur_block_rowptr = (pangulu_inblock_ptr *)(block_csc_remote[target_rank] + arr_len); + cur_block_colidx = (pangulu_inblock_idx *)(block_csc_remote[target_rank] + arr_len + sizeof(pangulu_inblock_ptr) * (block_order + 1)); + if(malloc_distbcsc_value){ + cur_block_value = (calculate_type *)( + block_csc_remote[target_rank] + arr_len + + sizeof(pangulu_inblock_ptr) * (block_order + 1) + + sizeof(pangulu_inblock_idx) * (remote_bnnzptr[bidx + 1] - remote_bnnzptr[bidx]) + ); + } + } + if(distcsc_value){ + cur_block_value[tmp_count[(level % q) * block_length_col + brow]] = distcsc_value[reorder_matrix_idx]; + }else if(malloc_distbcsc_value){ + cur_block_value[tmp_count[(level % q) * block_length_col + brow]] = 0; + } + reorder_matrix_idx++; + cur_block_colidx[tmp_count[(level % q) * block_length_col + brow]++] = row % block_order; + cur_block_rowptr[col_in_blc]++; + } + } + + for(pangulu_int32_t target_rank = 0; target_rank < nproc; target_rank++){ + pangulu_exblock_ptr* remote_bcolptr = csc_draft_remote[target_rank]; + pangulu_exblock_ptr* remote_bnnzptr = + csc_draft_remote[target_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[target_rank + 1] - nzblk_each_rank_ptr[target_rank]); + for (pangulu_int64_t bidx = remote_bcolptr[level]; bidx < remote_bcolptr[level + 1]; bidx++) + { + pangulu_int64_t tmp_stride = bidx * (block_order + 1) * sizeof(pangulu_inblock_ptr) + remote_bnnzptr[bidx] * (sizeof(pangulu_inblock_idx) + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type))); + pangulu_inblock_ptr *cur_csr_rpt = (pangulu_inblock_ptr *)(block_csc_remote[target_rank] + tmp_stride); + exclusive_scan_3(cur_csr_rpt, block_order + 1); + } + } + } + pangulu_free(__FILE__, __LINE__, tmp_count); + tmp_count = NULL; + } + pangulu_free(__FILE__, __LINE__, thread_pt); + thread_pt = NULL; + pangulu_free(__FILE__, __LINE__, block_row_pt); + block_row_pt = NULL; + pangulu_free(__FILE__, __LINE__, block_col_idx); + block_col_idx = NULL; + + if(rootproc_free_originmatrix){ + pangulu_free(__FILE__, __LINE__, distcsc_pointer); + pangulu_free(__FILE__, __LINE__, distcsc_index); + if(distcsc_value){ + pangulu_free(__FILE__, __LINE__, distcsc_value); // Don't set distcsc_value to NULL. + } + } + + // comm TAG=0 + pangulu_cm_sync(); + pangulu_exblock_ptr* nzblk_remote = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * nproc); + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + MPI_Request req; + nzblk_remote[remote_rank] = nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank]; + MPI_Isend(&nzblk_remote[remote_rank], 1, MPI_PANGULU_EXBLOCK_PTR, remote_rank, 0, MPI_COMM_WORLD, &req); + } + pangulu_exblock_ptr* nzblk_fetch = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * nproc); + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + MPI_Status stat; + MPI_Recv(&nzblk_fetch[fetch_rank], 1, MPI_PANGULU_EXBLOCK_PTR, fetch_rank, 0, MPI_COMM_WORLD, &stat); + } + pangulu_cm_sync(); + pangulu_free(__FILE__, __LINE__, nzblk_remote); + // printf("#%d 1.7\n", rank); + + // comm TAG=1 send csc_draft_remote + pangulu_cm_sync(); + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + pangulu_cm_isend( + csc_draft_remote[remote_rank], + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank]) + + sizeof(pangulu_exblock_ptr) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank] + 1), + remote_rank, 1, 10 + ); + } + char** bstruct_csc_fetch = pangulu_malloc(__FILE__, __LINE__, sizeof(char*) * nproc); + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + bstruct_csc_fetch[fetch_rank] = pangulu_malloc( + __FILE__, __LINE__, + sizeof(pangulu_exblock_ptr) * (block_length+1) + + sizeof(pangulu_exblock_idx) * nzblk_fetch[fetch_rank] + + sizeof(pangulu_exblock_ptr) * (nzblk_fetch[fetch_rank] + 1) + ); + pangulu_cm_recv( + bstruct_csc_fetch[fetch_rank], + sizeof(pangulu_exblock_ptr) * (block_length+1) + sizeof(pangulu_exblock_idx) * nzblk_fetch[fetch_rank] + sizeof(pangulu_exblock_ptr) * (nzblk_fetch[fetch_rank] + 1), + fetch_rank, 1, 10 + ); + } + pangulu_cm_sync(); + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + pangulu_free(__FILE__, __LINE__, csc_draft_remote[remote_rank]); + } + pangulu_free(__FILE__, __LINE__, csc_draft_remote); + csc_draft_remote = NULL; + + // comm TAG=2 send block_csc_remote + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + // MPI_Request req; + pangulu_int64_t send_size = sizeof(pangulu_inblock_ptr) * (block_order + 1) * (nzblk_each_rank_ptr[remote_rank + 1] - nzblk_each_rank_ptr[remote_rank]) + + sizeof(pangulu_inblock_idx) * (nnz_each_rank_ptr[remote_rank + 1] - nnz_each_rank_ptr[remote_rank]) + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * (nnz_each_rank_ptr[remote_rank + 1] - nnz_each_rank_ptr[remote_rank]); + pangulu_cm_isend(block_csc_remote[remote_rank], send_size, remote_rank, 2, 10); + } + pangulu_free(__FILE__, __LINE__, nzblk_each_rank_ptr); + nzblk_each_rank_ptr = NULL; + pangulu_free(__FILE__, __LINE__, nnz_each_rank_ptr); + nnz_each_rank_ptr = NULL; + char** block_csc_fetch = pangulu_malloc(__FILE__, __LINE__, sizeof(char*) * nproc); + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + MPI_Status stat; + pangulu_exblock_ptr* remote_bcolptr = bstruct_csc_fetch[fetch_rank]; + pangulu_exblock_idx* remote_browidx = bstruct_csc_fetch[fetch_rank] + sizeof(pangulu_exblock_ptr) * (block_length + 1); + pangulu_exblock_ptr* remote_bnnzptr = + bstruct_csc_fetch[fetch_rank] + + sizeof(pangulu_exblock_ptr) * (block_length + 1) + + sizeof(pangulu_exblock_idx) * (remote_bcolptr[block_length]); + + pangulu_int64_t recv_size = + sizeof(pangulu_inblock_ptr) * (block_order + 1) * remote_bcolptr[block_length] + + sizeof(pangulu_inblock_idx) * remote_bnnzptr[remote_bcolptr[block_length]] + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * remote_bnnzptr[remote_bcolptr[block_length]]; + block_csc_fetch[fetch_rank] = pangulu_malloc(__FILE__, __LINE__, recv_size); + // MPI_Recv(block_csc_fetch[fetch_rank], recv_size, MPI_CHAR, fetch_rank, 2, MPI_COMM_WORLD, &stat); + pangulu_cm_recv(block_csc_fetch[fetch_rank], recv_size, fetch_rank, 2, 10); + } + pangulu_cm_sync(); + for(pangulu_int32_t remote_rank = 0; remote_rank < nproc; remote_rank++){ + pangulu_free(__FILE__, __LINE__, block_csc_remote[remote_rank]); + } + pangulu_free(__FILE__, __LINE__, block_csc_remote); + block_csc_remote = NULL; + + pangulu_exblock_ptr* struct_bcolptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (block_length_col + 1)); + memset(struct_bcolptr, 0, sizeof(pangulu_exblock_ptr) * (block_length_col + 1)); + pangulu_exblock_ptr last_fetch_rank_ptr = 0; + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + pangulu_exblock_ptr* bstruct_fetch_pointer = bstruct_csc_fetch[fetch_rank]; + for(pangulu_exblock_idx brow_offset = 0; brow_offset < block_length; brow_offset++){ + if(fetch_rank * block_length + brow_offset > block_length_col){ + break; + } + struct_bcolptr[fetch_rank * block_length + brow_offset] = bstruct_fetch_pointer[brow_offset] + last_fetch_rank_ptr; + } + last_fetch_rank_ptr += bstruct_fetch_pointer[block_length]; + } + struct_bcolptr[block_length_col] = last_fetch_rank_ptr; + + pangulu_exblock_idx* struct_browidx = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * struct_bcolptr[block_length_col]); + pangulu_exblock_ptr* struct_bnnzptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (struct_bcolptr[block_length_col] + 1)); + pangulu_exblock_ptr last_fetch_bnnz_ptr = 0; + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + pangulu_exblock_ptr* bstruct_fetch_pointer = bstruct_csc_fetch[fetch_rank]; + pangulu_exblock_idx* bstruct_fetch_index = bstruct_csc_fetch[fetch_rank] + sizeof(pangulu_exblock_ptr) * (block_length+1); + pangulu_exblock_ptr* bstruct_fetch_nnzptr = bstruct_csc_fetch[fetch_rank] + sizeof(pangulu_exblock_ptr) * (block_length+1) + sizeof(pangulu_exblock_idx) * nzblk_fetch[fetch_rank]; + for(pangulu_exblock_ptr bidx_offset = 0; bidx_offset < nzblk_fetch[fetch_rank]; bidx_offset++){ + struct_browidx[struct_bcolptr[fetch_rank * block_length] + bidx_offset] = bstruct_fetch_index[bidx_offset]; + } + for(pangulu_exblock_ptr bidx_offset = 0; bidx_offset < nzblk_fetch[fetch_rank]; bidx_offset++){ + struct_bnnzptr[struct_bcolptr[fetch_rank * block_length] + bidx_offset] = bstruct_fetch_nnzptr[bidx_offset] + last_fetch_bnnz_ptr; + } + last_fetch_bnnz_ptr += bstruct_fetch_nnzptr[nzblk_fetch[fetch_rank]]; + } + struct_bnnzptr[struct_bcolptr[block_length_col]] = last_fetch_bnnz_ptr; + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + pangulu_free(__FILE__, __LINE__, bstruct_csc_fetch[fetch_rank]); + } + pangulu_free(__FILE__, __LINE__, bstruct_csc_fetch); + bstruct_csc_fetch = NULL; + pangulu_free(__FILE__, __LINE__, nzblk_fetch); + nzblk_fetch = NULL; + + char* block_csc = pangulu_malloc( + __FILE__, __LINE__, + sizeof(pangulu_inblock_ptr) * (block_order + 1) * struct_bcolptr[block_length_col] + + sizeof(pangulu_inblock_idx) * struct_bnnzptr[struct_bcolptr[block_length_col]] + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * struct_bnnzptr[struct_bcolptr[block_length_col]] + ); + for(pangulu_int32_t fetch_rank = 0; fetch_rank < nproc; fetch_rank++){ + pangulu_exblock_idx bidx_ub = struct_bcolptr[PANGULU_MIN((fetch_rank + 1) * block_length, block_length_col)]; + pangulu_exblock_idx bidx_lb = struct_bcolptr[PANGULU_MIN(fetch_rank * block_length, block_length_col)]; + pangulu_int64_t offset = + sizeof(pangulu_inblock_ptr) * (block_order + 1) * bidx_lb + + sizeof(pangulu_inblock_idx) * struct_bnnzptr[bidx_lb] + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * struct_bnnzptr[bidx_lb]; + pangulu_int64_t copy_size = + sizeof(pangulu_inblock_ptr) * (block_order + 1) * (bidx_ub - bidx_lb) + + sizeof(pangulu_inblock_idx) * (struct_bnnzptr[bidx_ub] - struct_bnnzptr[bidx_lb]) + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * (struct_bnnzptr[bidx_ub] - struct_bnnzptr[bidx_lb]); + memcpy(block_csc + offset, block_csc_fetch[fetch_rank], copy_size); + pangulu_free(__FILE__, __LINE__, block_csc_fetch[fetch_rank]); + } + pangulu_free(__FILE__, __LINE__, block_csc_fetch); + block_csc_fetch = NULL; + + pangulu_inblock_ptr** inblock_pointers = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_ptr*) * struct_bcolptr[block_length_col]); + pangulu_inblock_idx** inblock_indeces = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_inblock_idx*) * struct_bcolptr[block_length_col]); + calculate_type** inblock_values = NULL; + if(malloc_distbcsc_value){ + inblock_values = pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type*) * struct_bcolptr[block_length_col]); + } + + for(pangulu_exblock_ptr bidx = 0; bidx < struct_bcolptr[block_length_col]; bidx++){ + pangulu_int64_t offset = + sizeof(pangulu_inblock_ptr) * (block_order + 1) * bidx + + sizeof(pangulu_inblock_idx) * struct_bnnzptr[bidx] + + _PANGULU_SET_BVALUE_SIZE(sizeof(calculate_type)) * struct_bnnzptr[bidx]; + inblock_pointers[bidx] = block_csc + offset; + inblock_indeces[bidx] = block_csc + offset + + sizeof(pangulu_inblock_ptr) * (block_order + 1); + if(malloc_distbcsc_value){ + inblock_values[bidx] = block_csc + offset + + sizeof(pangulu_inblock_ptr) * (block_order + 1) + + sizeof(pangulu_inblock_idx) * (struct_bnnzptr[bidx + 1] - struct_bnnzptr[bidx]); + } + } + + *bcsc_struct_pointer = struct_bcolptr; + *bcsc_struct_index = struct_browidx; + *bcsc_struct_nnzptr = struct_bnnzptr; + *bcsc_inblock_pointers = inblock_pointers; + *bcsc_inblock_indeces = inblock_indeces; + if(malloc_distbcsc_value){ + *bcsc_values = inblock_values; + } + + bind_to_core(rank % sysconf(_SC_NPROCESSORS_ONLN)); + +#undef _PANGULU_SET_BVALUE_SIZE +#undef _PANGULU_SET_VALUE_SIZE +} + +void pangulu_cm_rank(pangulu_int32_t* rank){MPI_Comm_rank(MPI_COMM_WORLD, rank);} +void pangulu_cm_size(pangulu_int32_t* size){MPI_Comm_size(MPI_COMM_WORLD, size);} +void pangulu_cm_sync(){MPI_Barrier(MPI_COMM_WORLD);} +void pangulu_cm_bcast(void *buffer, int count, MPI_Datatype datatype, int root){MPI_Bcast(buffer, count, datatype, root, MPI_COMM_WORLD);} +void pangulu_cm_isend(char* buf, pangulu_int64_t count, pangulu_int32_t remote_rank, pangulu_int32_t tag, pangulu_int32_t tag_ub){ + MPI_Request req; + const pangulu_int64_t send_maxlen = 0x7FFFFFFF; + pangulu_int64_t send_times = PANGULU_ICEIL(count, send_maxlen); + for(pangulu_int64_t iter = 0; iter < send_times; iter++){ + int count_current = PANGULU_MIN((iter + 1) * send_maxlen, count) - iter * send_maxlen; + MPI_Isend(buf + iter * send_maxlen, count_current, MPI_CHAR, remote_rank, iter * tag_ub + tag, MPI_COMM_WORLD, &req); + } + if(send_times == 0){ + MPI_Isend(buf, 0, MPI_CHAR, remote_rank, tag, MPI_COMM_WORLD, &req); + } +} +void pangulu_cm_send(char* buf, pangulu_int64_t count, pangulu_int32_t remote_rank, pangulu_int32_t tag, pangulu_int32_t tag_ub){ + const pangulu_int64_t send_maxlen = 0x7FFFFFFF; + pangulu_int64_t send_times = PANGULU_ICEIL(count, send_maxlen); + for(pangulu_int64_t iter = 0; iter < send_times; iter++){ + int count_current = PANGULU_MIN((iter + 1) * send_maxlen, count) - iter * send_maxlen; + MPI_Send(buf + iter * send_maxlen, count_current, MPI_CHAR, remote_rank, iter * tag_ub + tag, MPI_COMM_WORLD); + } + if(send_times == 0){ + MPI_Send(buf, 0, MPI_CHAR, remote_rank, tag, MPI_COMM_WORLD); + } +} +void pangulu_cm_recv(char* buf, pangulu_int64_t count, pangulu_int32_t fetch_rank, pangulu_int32_t tag, pangulu_int32_t tag_ub){ + MPI_Status stat; + const pangulu_int64_t send_maxlen = 0x7FFFFFFF; + pangulu_int64_t recv_times = PANGULU_ICEIL(count, send_maxlen); + for(pangulu_int64_t iter = 0; iter < recv_times; iter++){ + int count_current = PANGULU_MIN((iter + 1) * send_maxlen, count) - iter * send_maxlen; + MPI_Recv(buf + iter * send_maxlen, count_current, MPI_CHAR, fetch_rank, iter * tag_ub + tag, MPI_COMM_WORLD, &stat); + } + if(recv_times == 0){ + MPI_Recv(buf, 0, MPI_CHAR, fetch_rank, tag, MPI_COMM_WORLD, &stat); + } +} +void pangulu_cm_sync_asym(int wake_rank) +{ + pangulu_int32_t sum_rank_size, rank; + pangulu_cm_rank(&rank); + pangulu_cm_size(&sum_rank_size); + if (rank == wake_rank) + { + for (int i = 0; i < sum_rank_size; i++) + { + if (i != wake_rank) + { + MPI_Send(&sum_rank_size, 1, MPI_INT, i, 0xCAFE, MPI_COMM_WORLD); + } + } + } + else + { + int mpi_buf_int; + int mpi_flag; + MPI_Status mpi_stat; + while (1) + { + mpi_flag = 0; + MPI_Iprobe(wake_rank, 0xCAFE, MPI_COMM_WORLD, &mpi_flag, &mpi_stat); + if (mpi_flag != 0 && mpi_stat.MPI_TAG == 0xCAFE) + { + MPI_Recv(&mpi_buf_int, 1, MPI_INT, wake_rank, 0xCAFE, MPI_COMM_WORLD, &mpi_stat); + if (mpi_buf_int == sum_rank_size) + { + break; + } + else + { + printf(PANGULU_E_ASYM); + exit(1); + } + } + usleep(50); + } + } + pangulu_cm_sync(); +} +void pangulu_cm_probe(MPI_Status *status) +{ + int have_msg=0; + do{ + MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &have_msg, status); + if(have_msg){ + return; + } + usleep(10); + }while(!have_msg); +} + +// void pangulu_cm_distribute_bcsc_to_distbcsc( +// pangulu_int32_t root_rank, +// int rootproc_free_originmatrix, +// pangulu_exblock_idx* n, + +// pangulu_exblock_ptr** bcsc_struct_pointer, +// pangulu_exblock_idx** bcsc_struct_index, +// pangulu_inblock_ptr** bcsc_struct_nnz, +// pangulu_inblock_ptr*** bcsc_inblock_pointers, +// pangulu_inblock_idx*** bcsc_inblock_indeces, +// calculate_type*** bcsc_values +// ){ + + +// } + +void pangulu_cm_distribute_csc_to_distcsc( + pangulu_int32_t root_rank, + int rootproc_free_originmatrix, + pangulu_exblock_idx* n, + pangulu_inblock_idx rowchunk_align, + pangulu_int32_t* distcsc_nproc, + pangulu_exblock_idx* n_loc, + + pangulu_exblock_ptr** distcsc_proc_nnzptr, + pangulu_exblock_ptr** distcsc_pointer, + pangulu_exblock_idx** distcsc_index, + calculate_type** distcsc_value +){ + struct timeval start_time; + pangulu_time_start(&start_time); + // printf("1.1\n"); + + + pangulu_int32_t nproc = 0; + pangulu_int32_t rank; + pangulu_cm_size(&nproc); + pangulu_cm_rank(&rank); + *distcsc_nproc = nproc; + pangulu_int64_t p = sqrt(nproc); + while ((nproc % p) != 0) + { + p--; + } + pangulu_int64_t q = nproc / p; + pangulu_cm_bcast(n, 1, MPI_PANGULU_EXBLOCK_IDX, root_rank); + // printf("#%d 1.2\n", rank); + + rowchunk_align *= q; + pangulu_exblock_idx col_per_rank = PANGULU_ICEIL(PANGULU_ICEIL(*n, rowchunk_align), nproc) * rowchunk_align; + + *distcsc_proc_nnzptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (nproc + 1)); + if(rank == root_rank){ + pangulu_exblock_ptr* columnpointer = *distcsc_pointer; + pangulu_exblock_idx* rowindex = *distcsc_index; + calculate_type* value_csc = NULL; + if(distcsc_value){ + value_csc = *distcsc_value; + } + (*distcsc_proc_nnzptr)[0] = 0; + // printf("#%d 1.3.1\n", rank); + for(pangulu_int32_t target_rank = 0; target_rank < nproc; target_rank++){ + // printf("#%d 1.3.2\n", rank); + pangulu_exblock_idx n_loc_remote = PANGULU_MIN(col_per_rank * (target_rank + 1), *n) - PANGULU_MIN(col_per_rank * target_rank, *n); + (*distcsc_proc_nnzptr)[target_rank + 1] = columnpointer[PANGULU_MIN(col_per_rank * (target_rank + 1), *n)]; + if(rank == target_rank){ + *n_loc = n_loc_remote; + // printf("#%d n_loc = %d\n", rank, *n_loc); + + *distcsc_pointer = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (*n_loc + 1)); + memcpy(*distcsc_pointer, &columnpointer[PANGULU_MIN(col_per_rank * target_rank, *n)], sizeof(pangulu_exblock_ptr) * (*n_loc + 1)); + pangulu_exblock_idx col_offset = (*distcsc_pointer)[0]; + for(pangulu_exblock_idx col = 0; col < *n_loc + 1; col++){ + (*distcsc_pointer)[col] -= col_offset; + } + pangulu_exblock_ptr nnz_loc = (*distcsc_pointer)[*n_loc]; + *distcsc_index = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * nnz_loc); + memcpy(*distcsc_index, &rowindex[(*distcsc_proc_nnzptr)[target_rank]], sizeof(pangulu_exblock_idx) * nnz_loc); + + if(distcsc_value){ + *distcsc_value = pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nnz_loc); + memcpy(*distcsc_value, &value_csc[(*distcsc_proc_nnzptr)[target_rank]], sizeof(calculate_type) * nnz_loc); + } + }else{ + MPI_Send(&n_loc_remote, 1, MPI_PANGULU_EXBLOCK_IDX, target_rank, 0, MPI_COMM_WORLD); + MPI_Send(&columnpointer[PANGULU_MIN(col_per_rank * target_rank, *n)], n_loc_remote + 1, MPI_PANGULU_EXBLOCK_PTR, target_rank, 1, MPI_COMM_WORLD); + // MPI_Send( + // &rowindex[(*distcsc_proc_nnzptr)[target_rank]], + // (*distcsc_proc_nnzptr)[target_rank+1] - (*distcsc_proc_nnzptr)[target_rank], + // MPI_PANGULU_EXBLOCK_IDX, target_rank, 2, MPI_COMM_WORLD + // ); + pangulu_cm_send(&rowindex[(*distcsc_proc_nnzptr)[target_rank]], sizeof(pangulu_exblock_idx) * ((*distcsc_proc_nnzptr)[target_rank+1] - (*distcsc_proc_nnzptr)[target_rank]), target_rank, 2, 10); + if(distcsc_value){ + // MPI_Send( + // &value_csc[(*distcsc_proc_nnzptr)[target_rank]], + // (*distcsc_proc_nnzptr)[target_rank+1] - (*distcsc_proc_nnzptr)[target_rank], + // MPI_VAL_TYPE, target_rank, 3, MPI_COMM_WORLD + // ); + pangulu_cm_send(&value_csc[(*distcsc_proc_nnzptr)[target_rank]], sizeof(calculate_type) * ((*distcsc_proc_nnzptr)[target_rank+1] - (*distcsc_proc_nnzptr)[target_rank]), target_rank, 3, 10); + // printf("Sent %d->%d\n", rank, target_rank); + }else{ + int nouse = 0; + MPI_Send(&nouse, 1, MPI_INT, target_rank, 4, MPI_COMM_WORLD); + } + } + // printf("#%d 1.3.3\n", rank); + } + MPI_Bcast(*distcsc_proc_nnzptr, nproc+1, MPI_PANGULU_EXBLOCK_PTR, root_rank, MPI_COMM_WORLD); + if(rootproc_free_originmatrix){ + pangulu_free(__FILE__, __LINE__, columnpointer); + pangulu_free(__FILE__, __LINE__, rowindex); + if(distcsc_value){ + pangulu_free(__FILE__, __LINE__, value_csc); + } + } + // printf("#%d 1.3.4\n", rank); + }else{ + // printf("#%d 1.4.1\n", rank); + MPI_Status mpi_stat; + MPI_Recv(n_loc, 1, MPI_PANGULU_EXBLOCK_IDX, root_rank, 0, MPI_COMM_WORLD, &mpi_stat); + // printf("#%d n_loc = %d\n", rank, *n_loc); + + *distcsc_pointer = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (*n_loc + 1)); + MPI_Recv(*distcsc_pointer, *n_loc+1, MPI_PANGULU_EXBLOCK_PTR, root_rank, 1, MPI_COMM_WORLD, &mpi_stat); + pangulu_exblock_idx col_offset = (*distcsc_pointer)[0]; + for(pangulu_exblock_idx col = 0; col < *n_loc + 1; col++){ + (*distcsc_pointer)[col] -= col_offset; + } + pangulu_exblock_ptr nnz_loc = (*distcsc_pointer)[*n_loc]; + *distcsc_index = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * nnz_loc); + // MPI_Recv(*distcsc_index, nnz_loc, MPI_PANGULU_EXBLOCK_IDX, root_rank, 2, MPI_COMM_WORLD, &mpi_stat); + pangulu_cm_recv(*distcsc_index, sizeof(pangulu_exblock_idx) * nnz_loc, root_rank, 2, 10); + // printf("#%d 1.4.2\n", rank); + + MPI_Probe(root_rank, MPI_ANY_TAG, MPI_COMM_WORLD, &mpi_stat); + // printf("Probe\n"); + if((mpi_stat.MPI_TAG%10) == 3){ + *distcsc_value = pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nnz_loc); + // MPI_Recv(*distcsc_value, nnz_loc, MPI_VAL_TYPE, root_rank, 3, MPI_COMM_WORLD, &mpi_stat); + pangulu_cm_recv(*distcsc_value, sizeof(calculate_type) * nnz_loc, root_rank, 3, 10); + }else if(mpi_stat.MPI_TAG == 4){ + int nouse = 0; + MPI_Recv(&nouse, 1, MPI_INT, root_rank, 4, MPI_COMM_WORLD, &mpi_stat); + } + // printf("#%d 1.4.25\n", rank); + + MPI_Bcast(*distcsc_proc_nnzptr, nproc+1, MPI_PANGULU_EXBLOCK_PTR, root_rank, MPI_COMM_WORLD); + // printf("#%d 1.4.3\n", rank); + } + // printf("#%d 1.5\n", rank); + + // printf("[PanguLU LOG] pangulu_cm_distribute_csc_to_distcsc time : %.2lf ms\n", pangulu_time_stop(&start_time) * 1e3); +} + +void pangulu_convert_csr_to_csc( + int free_csrmatrix, + pangulu_exblock_idx n, + pangulu_exblock_ptr** csr_pointer, + pangulu_exblock_idx** csr_index, + calculate_type** csr_value, + pangulu_exblock_ptr** csc_pointer, + pangulu_exblock_idx** csc_index, + calculate_type** csc_value +){ + struct timeval start_time; + pangulu_time_start(&start_time); + + pangulu_exblock_ptr* rowpointer = *csr_pointer; + pangulu_exblock_idx* columnindex = *csr_index; + calculate_type* value = NULL; + if(csr_value){ + value = *csr_value; + } + + pangulu_exblock_ptr nnz = rowpointer[n]; + + pangulu_exblock_ptr* columnpointer = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_ptr* aid_ptr_arr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_idx* rowindex = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * nnz); + calculate_type* value_csc = NULL; + if(value){ + value_csc = pangulu_malloc(__FILE__, __LINE__, sizeof(calculate_type) * nnz); + } + + memset(columnpointer, 0, sizeof(pangulu_exblock_ptr) * (n + 1)); + for(pangulu_exblock_idx row = 0; row < n; row++){ + for(pangulu_exblock_ptr idx = rowpointer[row]; idx < rowpointer[row+1]; idx++){ + pangulu_exblock_idx col = columnindex[idx]; + columnpointer[col+1]++; + } + } + for(pangulu_exblock_idx col = 0; col < n; col++){ + columnpointer[col+1] += columnpointer[col]; + } + memcpy(aid_ptr_arr, columnpointer, sizeof(pangulu_exblock_ptr) * (n + 1)); + + if(value){ + for(pangulu_exblock_idx row = 0; row < n; row++){ + for(pangulu_exblock_ptr idx = rowpointer[row]; idx < rowpointer[row+1]; idx++){ + pangulu_exblock_idx col = columnindex[idx]; + rowindex[aid_ptr_arr[col]] = row; + value_csc[aid_ptr_arr[col]] = value[idx]; + aid_ptr_arr[col]++; + } + } + }else{ + for(pangulu_exblock_idx row = 0; row < n; row++){ + for(pangulu_exblock_ptr idx = rowpointer[row]; idx < rowpointer[row+1]; idx++){ + pangulu_exblock_idx col = columnindex[idx]; + rowindex[aid_ptr_arr[col]] = row; + aid_ptr_arr[col]++; + } + } + } + + pangulu_free(__FILE__, __LINE__, aid_ptr_arr); + if(free_csrmatrix){ + pangulu_free(__FILE__, __LINE__, *csr_pointer); + pangulu_free(__FILE__, __LINE__, *csr_index); + pangulu_free(__FILE__, __LINE__, *csr_value); + *csr_pointer = NULL; + *csr_index = NULL; + *csr_value = NULL; + } + *csc_pointer = columnpointer; + *csc_index = rowindex; + if(csc_value){ + *csc_value = value_csc; + } + // printf("[PanguLU LOG] pangulu_convert_csr_to_csc time : %.2lf ms\n", pangulu_time_stop(&start_time) * 1e3); +} + +void pangulu_convert_ordered_halfsymcsc_to_csc_struct( + int free_halfmatrix, + int if_colsort, + pangulu_exblock_idx n, + pangulu_exblock_ptr** half_csc_pointer, + pangulu_exblock_idx** half_csc_index, + pangulu_exblock_ptr** csc_pointer, + pangulu_exblock_idx** csc_index +){ + pangulu_exblock_ptr* half_ptr = *half_csc_pointer; + pangulu_exblock_idx* half_idx = *half_csc_index; + pangulu_exblock_ptr nnz = half_ptr[n]; + pangulu_exblock_ptr* at_ptr = (pangulu_exblock_ptr*)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + memset(at_ptr, 0, sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_idx* at_idx = (pangulu_exblock_idx*)pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * nnz); + for (pangulu_exblock_idx col = 0; col < n; col++) { + for (pangulu_exblock_ptr row_idx = half_ptr[col]; row_idx < half_ptr[col + 1]; row_idx++) { + pangulu_exblock_idx row = half_idx[row_idx]; + at_ptr[row + 1]++; + } + } + for (pangulu_exblock_idx i = 1; i <= n; i++) { + at_ptr[i] += at_ptr[i - 1]; + } + + pangulu_exblock_ptr* a_aid_ptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + memcpy(a_aid_ptr, half_ptr, sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_ptr* at_aid_ptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + memcpy(at_aid_ptr, at_ptr, sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_idx stride = 10000; + // printf("stride = %d\n", stride); + pangulu_exblock_idx n_tile = PANGULU_ICEIL(n,stride); + for(pangulu_exblock_idx i_tile = 0; i_tile < n_tile; i_tile++){ + pangulu_exblock_idx col_end = PANGULU_MIN((i_tile + 1) * stride, n); + for(pangulu_exblock_idx row = 0; row < n; row++){ + pangulu_exblock_idx col; + while((a_aid_ptr[row] < half_ptr[row+1]) && ((col = half_idx[a_aid_ptr[row]]) < col_end)){ + at_idx[at_aid_ptr[col]] = row; + at_aid_ptr[col]++; + a_aid_ptr[row]++; + } + } + } + pangulu_free(__FILE__, __LINE__, at_aid_ptr); + pangulu_free(__FILE__, __LINE__, a_aid_ptr); + + pangulu_exblock_ptr* full_ptr = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_ptr) * (n + 1)); + pangulu_exblock_idx* full_idx = pangulu_malloc(__FILE__, __LINE__, sizeof(pangulu_exblock_idx) * (2 * nnz - n)); + full_ptr[0] = 0; + for(pangulu_exblock_idx row = 0; row < n; row++){ + full_ptr[row + 1] = (half_ptr[row + 1] - half_ptr[row]) + (at_ptr[row + 1] - at_ptr[row]) - 1; + } + for(pangulu_exblock_idx row = 0; row < n; row++){ + full_ptr[row + 1] += full_ptr[row]; + } + #pragma omp parallel for + for(pangulu_exblock_idx row = 0; row < n; row++){ + memcpy(&full_idx[full_ptr[row]], &at_idx[at_ptr[row]], sizeof(pangulu_exblock_idx) * (at_ptr[row+1] - at_ptr[row])); + memcpy(&full_idx[full_ptr[row] + (at_ptr[row+1] - at_ptr[row]) - 1], &half_idx[half_ptr[row]], sizeof(pangulu_exblock_idx) * (half_ptr[row+1] - half_ptr[row])); + } + + pangulu_free(__FILE__, __LINE__, at_ptr); + pangulu_free(__FILE__, __LINE__, at_idx); + + if (free_halfmatrix) { + pangulu_free(__FILE__, __LINE__, *half_csc_pointer); + pangulu_free(__FILE__, __LINE__, *half_csc_index); + *half_csc_pointer = NULL; + *half_csc_index = NULL; + } + + if(if_colsort){ + pangulu_int32_t rank, nproc; + pangulu_cm_rank(&rank); + pangulu_cm_size(&nproc); + int nthread_sort = 2; + bind_to_core((rank * nthread_sort) % sysconf(_SC_NPROCESSORS_ONLN)); + #pragma omp parallel num_threads(nthread_sort) + { + bind_to_core((rank * nthread_sort + omp_get_thread_num()) % sysconf(_SC_NPROCESSORS_ONLN)); + } + pangulu_sort_exblock_struct(n, at_ptr, at_idx, nthread_sort); + bind_to_core(rank % sysconf(_SC_NPROCESSORS_ONLN)); + } + + *csc_pointer = full_ptr; + *csc_index = full_idx; +} + +void pangulu_convert_bcsc_fill_value_to_struct( + int free_valuebcsc, + pangulu_exblock_idx n, + pangulu_inblock_idx nb, + + pangulu_exblock_ptr* value_bcsc_struct_pointer, + pangulu_exblock_idx* value_bcsc_struct_index, + pangulu_exblock_ptr* value_bcsc_struct_nnzptr, + pangulu_inblock_ptr** value_bcsc_inblock_pointers, + pangulu_inblock_idx** value_bcsc_inblock_indeces, + calculate_type** value_bcsc_values, + + pangulu_exblock_ptr* struct_bcsc_struct_pointer, + pangulu_exblock_idx* struct_bcsc_struct_index, + pangulu_exblock_ptr* struct_bcsc_struct_nnzptr, + pangulu_inblock_ptr** struct_bcsc_inblock_pointers, + pangulu_inblock_idx** struct_bcsc_inblock_indeces, + calculate_type** struct_bcsc_values +){ + struct timeval start_time; + pangulu_time_start(&start_time); + + pangulu_exblock_idx block_length = PANGULU_ICEIL(n , nb); + + for(pangulu_exblock_idx sp = 0; sp < block_length; sp++) + { + pangulu_exblock_ptr ssi = struct_bcsc_struct_pointer[sp]; + for(pangulu_exblock_ptr vsi = value_bcsc_struct_pointer[sp]; vsi < value_bcsc_struct_pointer[sp + 1]; vsi++) + { + while((struct_bcsc_struct_index[ssi] != value_bcsc_struct_index[vsi]) && (ssi < struct_bcsc_struct_pointer[sp+1])) + { + ssi++; + } + if(ssi >= struct_bcsc_struct_pointer[sp+1]){ + break; + } + for(pangulu_exblock_idx ip = 0; ip < nb; ip++) + { + pangulu_inblock_ptr sii = struct_bcsc_inblock_pointers[ssi][ip]; + for(pangulu_exblock_ptr vii = value_bcsc_inblock_pointers[vsi][ip]; vii < value_bcsc_inblock_pointers[vsi][ip + 1]; vii++) + { + while((struct_bcsc_inblock_indeces[ssi][sii] != value_bcsc_inblock_indeces[vsi][vii]) && (sii < struct_bcsc_inblock_pointers[ssi][ip+1])) + { + sii++; + } + if(sii >= struct_bcsc_inblock_pointers[ssi][ip+1]){ + break; + } + struct_bcsc_values[ssi][sii] = value_bcsc_values[vsi][vii]; + } + } + } + } + + if(free_valuebcsc) + { + if(value_bcsc_struct_pointer[block_length] > 0){ + pangulu_free(__FILE__, __LINE__, value_bcsc_inblock_pointers[0]); + } + pangulu_free(__FILE__, __LINE__, value_bcsc_inblock_pointers); + pangulu_free(__FILE__, __LINE__, value_bcsc_inblock_indeces); + pangulu_free(__FILE__, __LINE__, value_bcsc_values); + pangulu_free(__FILE__, __LINE__, value_bcsc_struct_pointer); + pangulu_free(__FILE__, __LINE__, value_bcsc_struct_index); + pangulu_free(__FILE__, __LINE__, value_bcsc_struct_nnzptr); + } + + // printf("[PanguLU LOG] pangulu_convert_bcsc_fill_value_to_struct time : %.2lf ms\n", pangulu_time_stop(&start_time) * 1e3); +} + void pangulu_bip_init(pangulu_block_info_pool **BIP, pangulu_int64_t map_index_not_included) { // BIP : block info pool if(!BIP){ @@ -493,14 +1624,24 @@ void pangulu_read_pangulu_origin_smatrix(pangulu_origin_smatrix *s, int wcs_n, l s->value = csr_value; } -void pangulu_time_start(pangulu_common *common) -{ - gettimeofday(&(common->start_time), NULL); -} +// void pangulu_time_start(pangulu_common *common) +// { +// gettimeofday(&(common->start_time), NULL); +// } -void pangulu_time_stop(pangulu_common *common) -{ - gettimeofday(&(common->stop_time), NULL); +// void pangulu_time_stop(pangulu_common *common) +// { +// gettimeofday(&(common->stop_time), NULL); +// } + +void pangulu_time_start(struct timeval* start){ + gettimeofday(start, NULL); +} +double pangulu_time_stop(struct timeval* start){ + struct timeval end; + gettimeofday(&end, NULL); + double time = ((double)end.tv_sec - start->tv_sec) + ((double)end.tv_usec - start->tv_usec) * 1e-6; + return time; } void pangulu_memcpy_zero_pangulu_smatrix_csc_value(pangulu_smatrix *s) @@ -560,7 +1701,7 @@ double pangulu_get_spend_time(pangulu_common *common) return time / 1000.0; } -void pangulu_transport_pangulu_smatrix_csc_to_csr(pangulu_smatrix *s) +void pangulu_transpose_pangulu_smatrix_csc_to_csr(pangulu_smatrix *s) { for (pangulu_int64_t i = 0; i < s->nnz; i++) { @@ -568,7 +1709,7 @@ void pangulu_transport_pangulu_smatrix_csc_to_csr(pangulu_smatrix *s) s->value[index] = s->value_csc[i]; } } -void pangulu_transport_pangulu_smatrix_csr_to_csc(pangulu_smatrix *s) +void pangulu_transpose_pangulu_smatrix_csr_to_csc(pangulu_smatrix *s) { for (pangulu_int64_t i = 0; i < s->nnz; i++) { @@ -1203,6 +2344,7 @@ void pangulu_sort_pangulu_matrix(pangulu_int64_t n, pangulu_exblock_ptr *rowpoin void pangulu_sort_pangulu_origin_smatrix(pangulu_origin_smatrix *s) { + #pragma omp parallel for for (pangulu_exblock_idx i = 0; i < s->row; i++) { pangulu_sort(s->columnindex, s->value, s->rowpointer[i], s->rowpointer[i + 1] - 1); diff --git a/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.cu b/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.cu index f0e6cb2..23393e7 100644 --- a/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.cu +++ b/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.cu @@ -2980,7 +2980,7 @@ __global__ void cuda_transform_d_to_s_col(pangulu_int64_t n, } } -// void pangulu_cuda_transport_kernel_csc_to_csr(pangulu_int64_t nnz, calculate_type *d_val_csr, pangulu_inblock_idx *d_idx, calculate_type *d_val_csc) +// void pangulu_cuda_transpose_kernel_csc_to_csr(pangulu_int64_t nnz, calculate_type *d_val_csr, pangulu_inblock_idx *d_idx, calculate_type *d_val_csc) // { // pangulu_int64_t num_threads = warp_size * 2; @@ -2990,7 +2990,7 @@ __global__ void cuda_transform_d_to_s_col(pangulu_int64_t n, // cudaDeviceSynchronize(); // } -// void pangulu_cuda_transport_kernel_csr_to_csc(pangulu_int64_t nnz, calculate_type *d_val_csc, pangulu_inblock_idx *d_idx, calculate_type *d_val_csr) +// void pangulu_cuda_transpose_kernel_csr_to_csc(pangulu_int64_t nnz, calculate_type *d_val_csc, pangulu_inblock_idx *d_idx, calculate_type *d_val_csr) // { // pangulu_int64_t num_threads = warp_size * 2; diff --git a/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.h b/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.h index 0cffc47..595bda5 100644 --- a/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.h +++ b/src/platforms/02_GPU/01_CUDA/000_CUDA/pangulu_cuda.h @@ -131,9 +131,9 @@ void pangulu_gessm_cuda_kernel_v11(pangulu_int64_t n, pangulu_inblock_idx *a_rowindex, calculate_type *a_value); -// void pangulu_cuda_transport_kernel_csc_to_csr(pangulu_int64_t nnz, calculate_type *d_val_csr, pangulu_int64_t *d_idx, calculate_type *d_val_csc); +// void pangulu_cuda_transpose_kernel_csc_to_csr(pangulu_int64_t nnz, calculate_type *d_val_csr, pangulu_int64_t *d_idx, calculate_type *d_val_csc); -// void pangulu_cuda_transport_kernel_csr_to_csc(pangulu_int64_t nnz, calculate_type *d_val_csc, pangulu_int64_t *d_idx, calculate_type *d_val_csr); +// void pangulu_cuda_transpose_kernel_csr_to_csc(pangulu_int64_t nnz, calculate_type *d_val_csc, pangulu_int64_t *d_idx, calculate_type *d_val_csr); void pangulu_getrf_cuda_kernel(pangulu_int64_t n, pangulu_int64_t nnza,