[ADD] Added automation for psb_spmm test

This commit is contained in:
Stack-1
2025-04-15 09:32:14 +02:00
parent c09920c450
commit aa91c924da
111 changed files with 17395 additions and 12779 deletions
+2 -2
View File
@@ -6,7 +6,7 @@ include $(INCDIR)/Make.inc.psblas
# Libraries used
#
LIBDIR = $(INSTALLDIR)/lib/
PSBLAS_LIB = -L$(LIBDIR) -lpsb_util -lpsb_prec -lpsb_base
PSBLAS_LIB = -L$(LIBDIR) -lpsb_util -lpsb_base
LDLIBS = $(PSBLDLIBS)
FINCLUDES=$(FMFLAG)$(MODDIR) $(FMFLAG).
@@ -30,7 +30,7 @@ runsd:
psb_spmm_test:
@$(FLINK) $(LOPT) psb_spmm_test.f90 -o psb_spmm_test -I../../modules/ -I. $(PSBLAS_LIB) $(LDLIBS)
@$(FLINK) $(LOPT) psb_spmm_test.f90 spmm.f90 -o psb_spmm_test -I../../modules/ -I. $(PSBLAS_LIB) $(LDLIBS)
@mv psb_spmm_test $(EXEDIR)
@printf "$(BLUE)[INFO]\tTesting files generated correctly$(END_COLOUR)\n"
+51 -11
View File
@@ -1,5 +1,5 @@
# Introduction
This is a directory developed by Luca Pepè Sciarria and Simone Staccone froma Tor Vergata University to start to create some unit tests for PSBLAS 3.9, in particular for psb_spmm routine.
This is a directory developed by Luca Pepè Sciarria and Simone Staccone froma Tor Vergata University to start to create some unit tests for PSBLAS 3.9, in particular for ```psb_spmm``` routine.
## Environment
These tests are developed using a linux environment, in particular Rocky Linux 9.5 (Blue Onyx).
@@ -16,20 +16,27 @@ In order to have the exact same environment used for testing compile PSBALS libr
## Getting started
Steps to reproduce the tests:
- make
- insert the matrix files inside the matrix/ directory (or create one if it doesn't exists; psblas3/test/spmm/matrix/)
- run ./runs/psb_spmm_test
- ...
- Compile the code using ``` make ```
- Insert the matrix files inside the matrix/ directory (or create one if it doesn't exists; psblas3/test/spmm/matrix/)
- Launch the script autotest.sh
- Check the output log file test_log.txt to collect results
## Test goal
Check the correctness of the matrix-vector multiplication $y = Ax$ using the **psb_spmm** routine, checking for all the test suite cases.
## Test Suite
**A** matrixes are located in the matrix/ directory
|Matrix|File Name|Type|
|:-:|:-:|:-:|
|$A_1$|1138_bus.mtx|Sparse|
### Overall Analysys
THe subroutine psb_spmm materialize in three different procedures:
```psb_sspmm```, ```psb_sspmv```, ```psb_sspmv_vect```. The focus is on testing the ```psb_sspmv``` one, so as first step let's analyze the signature of the function to study a satisfyng input parameter space. The signature of the function is:
```fortran
psb_sspmv(alpha, a, x, beta, y,&
& desc_a, info, trans, work,doswap)
```
In order to have a black-box approach and to consider only the functionalities of the routine, the parameters ***work*** and ***doswap*** are not considered during this tests, since they are used in situation that presents internally to the library code. Moreover, info it's an output parameter used to signal some kind of error, therefore it is not part of the input space.
There are seven parameters left. In the following tables are highlighted the values assigned to each parameter. THe test are runned composing a Cartesian product of all the possible values assigned to each parameter.
### Parameters Values
**x** vectors are located in the vectors/ directory. They are generated randomly using the same seed and then saved on different files based on their characteristics. The size of the vector is choosen accordingly to the size of the matrix column space considered for the single test instance.
|Vector|File Name|Coefficients|Coefficients Description|
|:-:|:-:|:-:|:-:|
@@ -38,8 +45,41 @@ Check the correctness of the matrix-vector multiplication $y = Ax$ using the **p
|$x_3$|x3.txt|$x_i \ne 0, \forall i$|Random coefficients
|$x_4$|x4.txt|$x_i = 0, \forall i$|Null coefficients
**y** vectors are located in the vectors/ directory. They are generated randomly using the same seed and then saved on different files based on their characteristics. The size of the vector is choosen accordingly to the size of the matrix rows space considered for the single test instance.
|Vector|File Name|Coefficients|Coefficients Description|
|:-:|:-:|:-:|:-:|
|$y_1$|y1.txt|$y_i> 0, \forall i$|Positive coefficients|
|$y_2$|y2.txt|$y_i < 0, \forall i$|Negative coefficients
|$y_3$|y3.txt|$y_i \ne 0, \forall i$|Random coefficients
|$y_4$|y4.txt|$y_i = 0, \forall i$|Null coefficients
**$\alpha$**
|$\alpha$|Value|Coefficients Description|
|:-:|:-:|:-:|
|$\alpha_1$|1.0|Positive value|
|$\alpha_2$|-1.0|Negative value|
|$\alpha_3$|0.0|Null value|
**$\beta$**
|$\alpha$|Value|Coefficients Description|
|:-:|:-:|:-:|
|$\beta_1$|1.0|Positive value|
|$\beta_2$|-1.0|Negative value|
|$\beta_3$|0.0|Null value|
**trans**
## Output
The results of the computation will be saved on different files based on the instance of the test considered. In particular the naming conventiona format the output file as sol_m#_x#_y#.mtx, where each # is a number choosen w.r.t. the test instance. (Ex. sol_m1_x1_y1.mtx is the solution computed using the first matrix file, the first x vector file and the first y vector file).
The ouput files generated by the test are automatically compared by the autotest.sh script, but if it is needed to manually run the test here it is the naming convenction used.
The results of the computation will be saved on different files based on the instance of the test considered. In particular the naming conventiona format the output file as sol_m#_x#_y#_a#_b#.mtx, where each # is a number choosen w.r.t. the test instance. (Ex. sol_m1_x1_y1_a1_b1.mtx is the solution computed using the first matrix file, the first x vector file , the first y vector file, alpha = 1.0 and beta = 1.0). Moreover, the files will be saved in the serial/ directory if the program is launched using 1 process or in parrallel/ directory if the program is launched with more than one process.
## Notes
For now only integer multiplication is tested and on a single matrix
For now only integer multiplication is tested and on a single matrix
## TODO
- Update docs
- Parametrize also on trans parameter
- Create the script autotest.sh
- Write the I/O output on log file
- ...
+228 -183
View File
@@ -2,248 +2,293 @@
!! Check the README.md to see all details about the tests.
!!
!! Author: Luca Pepé Sciarria, Staccone Simone (Tor Vergata University)
program psb_spmm_test
use psb_base_mod
use psb_util_mod
implicit none
! input parameters
character(len=256) :: mtx_file, file_name, name
! Testing parameters
character(len=256),dimension(2) :: mtx_files
! sparse matrices
type(psb_sspmat_type) :: a
type(psb_lsspmat_type) :: aux_a
! vectors
type(psb_s_vect_type) :: x, y
! matrix descriptor data structure
type(psb_desc_type) :: desc_a
! communication context
type(psb_ctxt_type) :: ctxt
integer(psb_ipk_) :: my_rank, np, info, err_act
! matrix parameters
integer(psb_ipk_) :: m, n, nnz
integer(psb_ipk_) :: nr, nt ! In BLOCK ROWS distributin, the number of rows
real(psb_spk_), allocatable :: x_global(:), y_global(:)
integer(psb_ipk_) :: i
name = "psb_spmm_test" ! Name of the program to output in case of error
info = psb_success_
mtx_file = "matrix/1138_bus.mtx"
mtx_files(1) = "matrix/1138_bus.mtx"
call psb_init(ctxt)
call psb_info(ctxt,my_rank,np)
if (my_rank < 0) then
! This should not happen, but just in case
call psb_error(ctxt)
endif
if (my_rank == psb_root_) then
write(psb_out_unit,*) 'Welcome to PSBLAS version: ',psb_version_string_
write(psb_out_unit,*) 'This is the ',trim(name),' sample program'
end if
call mm_mat_read(aux_a,info,filename=mtx_file)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error while reading matric ", mtx_file
goto 9999
end if
module psb_spmm_test
! part_block it's a macro defined in psb_blockpart_mod to identify BLOCK ROWS distribution
call psb_matdist(aux_a, a, ctxt,desc_a,info,fmt="COO",parts=part_block)
contains
m = aux_a%get_nrows()
n = aux_a%get_ncols()
nnz = aux_a%get_nzeros()
subroutine psb_spmm_kernel(mtx_file,x_file, y_file, alpha, beta, ctxt)
use psb_base_mod
use psb_util_mod
call psb_bcast(ctxt,m)
call psb_bcast(ctxt,n)
call psb_bcast(ctxt,nnz)
implicit none
if(my_rank == psb_root_) then
write(psb_out_unit,*) "Matrix stats"
write(psb_out_unit,*) "ROWS:", m
write(psb_out_unit,*) "COLS:", n
write(psb_out_unit,*) "NNZ: ", nnz
end if
! input parameters
character(len = *), intent(in) :: mtx_file, x_file, y_file
real(psb_spk_), intent(in) :: alpha, beta
! Generate random array for b using always the same seed
if(my_rank == psb_root_) then
allocate(x_global(n))
allocate(y_global(n))
call generate_vectors(n) ! True for x
call mm_array_read(x_global,info,filename="vectors/x1.mtx")
call mm_array_read(y_global,info,filename="vectors/y1.mtx")
end if
character(len=:), allocatable :: output_file_name
call psb_geall(x,desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error allocating x data structure"
goto 9999
end if
! sparse matrices
type(psb_sspmat_type) :: a
type(psb_lsspmat_type) :: aux_a
! Populate x class using data from x_global vector
call psb_scatter(x_global,x,desc_a,info,root=psb_root_)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in psb_scatter to populate x data structure"
goto 9999
end if
! vectors
type(psb_s_vect_type) :: x, y
call psb_geall(y,desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error allocating y data structure"
goto 9999
end if
! matrix descriptor data structure
type(psb_desc_type) :: desc_a
! Populate y class using data from y_global vector
call psb_scatter(y_global,y,desc_a,info,root=psb_root_)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in psb_scatter to populate y data structure"
goto 9999
end if
! communication context
type(psb_ctxt_type), intent(in) :: ctxt
integer(psb_ipk_) :: my_rank, np, info, err_act
! matrix parameters
integer(psb_ipk_) :: rows, cols, nnz
integer(psb_ipk_) :: nr, nt ! In BLOCK ROWS distributin, the number of rows
! y = alpha * A * x + betha * y
call psb_spmm(sone,a,x,sone,y,desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in psb_spmm routine"
goto 9999
end if
real(psb_spk_), allocatable :: x_global(:), y_global(:)
integer(psb_ipk_) :: i
! Save result to output file
call mm_array_write(y,"Result vector",info,filename="sol_m1_x1_y1.mtx")
! Deallocate
call psb_gefree(x, desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in vector x free routine"
goto 9999
end if
call psb_gefree(y, desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in vector y free routine"
goto 9999
end if
call psb_spfree(a, desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in matrix A free routine"
goto 9999
end if
call psb_cdfree(desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in matrix descriptor free routine"
goto 9999
end if
deallocate(x_global)
deallocate(y_global)
call psb_exit(ctxt)
stop
info = psb_success_
! Error handling
9999 call psb_error(ctxt)
call psb_errpush(info,name)
call psb_error_handler(ctxt,err_act)
call psb_exit(ctxt)
stop
call psb_info(ctxt,my_rank,np)
if (my_rank < 0) then
! This should not happen, but just in case
call psb_error(ctxt)
endif
call mm_mat_read(aux_a,info,filename=mtx_file)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error while reading matric ", mtx_file
goto 9999
end if
contains
! part_block it's a macro defined in psb_blockpart_mod to identify BLOCK ROWS distribution
call psb_matdist(aux_a, a, ctxt,desc_a,info,fmt="COO",parts=part_block)
rows = aux_a%get_nrows()
cols = aux_a%get_ncols()
nnz = aux_a%get_nzeros()
call psb_bcast(ctxt,rows)
call psb_bcast(ctxt,cols)
call psb_bcast(ctxt,nnz)
! Generate random array for b using always the same seed
if(my_rank == psb_root_) then
allocate(x_global(cols))
allocate(y_global(rows))
call mm_array_read(x_global,info,filename=x_file)
call mm_array_read(y_global,info,filename=y_file)
end if
call psb_geall(x,desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error allocating x data structure"
goto 9999
end if
! Populate x class using data from x_global vector
call psb_scatter(x_global,x,desc_a,info,root=psb_root_)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in psb_scatter to populate x data structure"
goto 9999
end if
call psb_geall(y,desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error allocating y data structure"
goto 9999
end if
! Populate y class using data from y_global vector
call psb_scatter(y_global,y,desc_a,info,root=psb_root_)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in psb_scatter to populate y data structure"
goto 9999
end if
! y = alpha * A * x + beta * y
call psb_spmm(alpha,a,x,beta,y,desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in psb_spmm routine"
goto 9999
end if
! Make the root process be the one that saves everything on file
if(np == 1) then
output_file_name = "serial/"
else
output_file_name = "parallel/"
end if
output_file_name = output_file_name // "sol_" // x_file(9:10) // "_" // y_file(9:10)
if(alpha == sone) then
output_file_name = output_file_name // "_a1"
else if(alpha == -sone) then
output_file_name = output_file_name // "_a2"
else if(alpha == szero) then
output_file_name = output_file_name // "_a3"
end if
if(beta == sone) then
output_file_name = output_file_name // "_b1.mtx"
else if(beta == -sone) then
output_file_name = output_file_name // "_b2.mtx"
else if(beta == szero) then
output_file_name = output_file_name // "_b3.mtx"
end if
! Save result to output file
call mm_array_write(y,"Result vector",info,filename=output_file_name)
! Deallocate
call psb_gefree(x, desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in vector x free routine"
goto 9999
end if
call psb_gefree(y, desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in vector y free routine"
goto 9999
end if
call psb_spfree(a, desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in matrix A free routine"
goto 9999
end if
call psb_cdfree(desc_a,info)
if(info /= psb_success_) then
write(psb_out_unit,*) "Error in matrix descriptor free routine"
goto 9999
end if
if(my_rank == 0) then
deallocate(x_global)
deallocate(y_global)
end if
return
! Error handling
9999 call psb_error(ctxt)
call psb_error_handler(ctxt,err_act)
stop
end subroutine
!> @brief Function to randomly generate x and y vectors
!! and save them on multiple files based on their
!! coefficients values.
!!
!! @param n The size of the vector.
subroutine generate_vectors(n)
subroutine generate_vectors(rows, cols)
use psb_base_mod
use psb_util_mod
implicit none
integer(psb_ipk_), intent(in) :: n
integer(psb_ipk_), allocatable :: x(:), y(:)
real(psb_spk_), allocatable :: v(:)
integer(psb_ipk_) :: i
allocate(x(n))
allocate(y(n))
allocate(v(2*n))
integer(psb_ipk_), intent(in) :: rows, cols
real(psb_spk_), allocatable :: x(:), y(:)
integer(psb_ipk_) :: i, info
allocate(x(rows))
allocate(y(cols))
call random_init(repeatable=.true.,image_distinct=.true.)
call random_number(v)
do i = 1,n
x(i) = int(v(i) * 100)
end do
do i = 1,n
y(i) = int(v(i+n) * 100)
end do
call random_number(x)
call random_number(y)
! Write only positive in x_1
call mm_array_write(x,"Positive vector",info,filename="vectors/x1.mtx")
call mm_array_write(y,"Positive vector",info,filename="vectors/y1.mtx")
! Write only negative in x_2
do i=1,n
do i=1,rows
x(i) = -x(i)
y(i) = -y(i)
end do
do i=1,cols
y(i) = -y(i)
end do
call mm_array_write(x,"Negative vector",info,filename="vectors/x2.mtx")
call mm_array_write(y,"Negative vector",info,filename="vectors/y2.mtx")
! Since numbers are less than one and always positive, we have to generate negative ones subtractiong 50
do i=1,n
do i=1,rows
x(i) = -x(i) ! Make the values positive again
x(i) = x(i) - 50
y(i) = -y(i) ! Make the values positive again
y(i) = y(i) - 50
x(i) = x(i) - 0.5
end do
do i=1,cols
y(i) = -y(i) ! Make the values positive again
y(i) = y(i) - 0.5
end do
! Write random in x_3
call mm_array_write(x,"Random vector",info,filename="vectors/x3.mtx")
call mm_array_write(y,"Random vector",info,filename="vectors/y3.mtx")
! Write zero in x_4
do i=1,n
do i=1,rows
x(i) = 0
y(i) = 0
end do
do i=1,cols
y(i) = 0
end do
call mm_array_write(x,"Null vector",info,filename="vectors/x4.mtx")
call mm_array_write(y,"Null vector",info,filename="vectors/y4.mtx")
deallocate(x)
deallocate(y)
deallocate(v)
end subroutine
end program
subroutine read_matrix_market_size(filename, rows, cols)
implicit none
character(len=*), intent(in) :: filename
integer, intent(out) :: rows, cols
integer :: ret, nnz
character(len=256) :: line
logical :: found
integer :: unit
! Open the file
open(newunit=unit, file=filename, status='old', action='read', iostat=ret)
if (ret /= 0) then
print *, 'Error opening file: ', filename
stop
end if
found = .false.
! Skip comment lines (starting with %)
do
read(unit, '(A)', iostat=ret) line
if (ret /= 0) exit
if (line(1:1) /= '%') then
read(line, *) rows, cols, nnz
found = .true.
exit
end if
end do
if (.not. found) then
print *, 'Error: header not found in Matrix Market file.'
stop
end if
close(unit)
end subroutine read_matrix_market_size
end module psb_spmm_test
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
program main
use psb_spmm_test
use psb_base_mod
implicit none
! matrix stats variables
integer(psb_ipk_) :: rows, cols
! MPI variables
integer(psb_ipk_) :: my_rank, np
! parameters array
character(len=64) :: x(4),y(4)
real(psb_ipk_) :: alpha(3), beta(3)
! cycle indexes variables
integer(psb_ipk_) :: i,j,k,h,l
! Communicator variable
type(psb_ctxt_type) :: ctxt
! Initialize parameters
x(1) = "vectors/x1.mtx"
x(2) = "vectors/x2.mtx"
x(3) = "vectors/x3.mtx"
x(4) = "vectors/x4.mtx"
y(1) = "vectors/y1.mtx"
y(2) = "vectors/y2.mtx"
y(3) = "vectors/y3.mtx"
y(4) = "vectors/y4.mtx"
alpha(1) = sone
alpha(2) = -sone
alpha(3) = szero
beta(1) = sone
beta(2) = -sone
beta(3) = szero
call psb_init(ctxt)
call psb_info(ctxt,my_rank,np)
if(my_rank == psb_root_) then
write(psb_out_unit,*) 'Welcome to PSBLAS version: ',psb_version_string_
write(psb_out_unit,*) 'This is the psb_spmm_test sample program'
call read_matrix_market_size("matrix/1138_bus.mtx", rows, cols)
call generate_vectors(rows,cols)
end if
call psb_barrier(ctxt)
!! 1138_bus matrix (sparse)
do i=1,4
do j=1,4
do k=1,3
do h=1,3
call psb_spmm_kernel(mtx_file="matrix/1138_bus.mtx",x_file=x(i), y_file=y(j), &
& alpha = alpha(k), beta = beta(h), ctxt = ctxt)
end do
end do
end do
end do
call psb_exit(ctxt)
return
end program main
BIN
View File
Binary file not shown.
-57
View File
@@ -5,63 +5,6 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void compare_files(const char *file1, const char *file2) {
FILE *file_s = fopen(file1, "r");
FILE *file_p = fopen(file2, "r");
if (!file_s || !file_p) {
perror("Error opening files");
exit(EXIT_FAILURE);
}
int n_s, n_p;
fscanf(file_s, "%d", &n_s);
fscanf(file_p, "%d", &n_p); // Assuming both files have the same number of lines
if (n_s != n_p) {
fprintf(stderr, "Error, differnet file sizes $d, $d", n_s, n_p);
exit(EXIT_FAILURE);
}
double value_s, value_p;
for (int i = 0; i < n_s; i++) {
fscanf(file_s, "%lf", &value_s);
fscanf(file_p, "%lf", &value_p);
if (value_s != value_p) {
printf("Index %d: %.2lf != %.2lf\n", i, value_s, value_p);
}
}
fclose(file_s);
fclose(file_p);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <partial_filename>\n", argv[0]);
return EXIT_FAILURE;
}
char file_s[256], file_p[256];
snprintf(file_s, sizeof(file_s), "%s_serial.txt", argv[1]);
snprintf(file_p, sizeof(file_p), "%s_parallel.txt", argv[1]);
compare_files(file_s, file_p);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff
+1138 -1138
View File
File diff suppressed because it is too large Load Diff