PaStiX Handbook  6.3.2
reentrant.c
Go to the documentation of this file.
1 /**
2  * @file reentrant.c
3  *
4  * @brief A reentrant example that runs two threads then run two instances of the solver in each thread.
5  *
6  * @copyright 2015-2023 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
7  * Univ. Bordeaux. All rights reserved.
8  *
9  * @version 6.3.2
10  * @author Mathieu Faverge
11  * @author Matias Hastaran
12  * @author Pierre Ramet
13  * @author Tony Delarue
14  * @author Alycia Lisito
15  * @date 2023-07-21
16  *
17  * @ingroup pastix_examples
18  * @code
19  *
20  */
21 #include <pthread.h>
22 #include <pastix.h>
23 #include <spm.h>
24 
25 /**
26  * Struct: solv_param
27  *
28  * Structure containing information to give
29  * to each thread.
30  */
31 typedef struct solve_param {
32  pastix_int_t iparm[IPARM_SIZE];
33  double dparm[DPARM_SIZE];
34  char *filename;
35  spm_driver_t driver;
36  int check;
37  int scatter;
38  int id;
39  int rc;
40 } solve_param_t;
41 
42 /**
43  * Function: solve_smp
44  *
45  * Thread routine to launch the solver
46  *
47  * Parameters:
48  * arg - a pointer to a <solve_param> structure.
49  */
50 static void *solve_smp(void *arg)
51 {
52  pastix_data_t *pastix_data = NULL; /*< Pointer to the storage structure required by pastix */
53  spmatrix_t *spm;
54  spmatrix_t spm2;
55  void *x, *b, *x0 = NULL;
56  size_t size;
57  int check;
58  int scatter;
59  int rc;
60  int nrhs = 1;
61  solve_param_t param = *(solve_param_t *)arg;
62 
63  if ( param.iparm[IPARM_THREAD_NBR] == -1) {
64  param.iparm[IPARM_THREAD_NBR] = 2;
65  }
66  check = param.check;
67  scatter = param.scatter;
68 
69  /**
70  * Startup PaStiX
71  */
72  {
73  int *bindtab = malloc( param.iparm[IPARM_THREAD_NBR] * sizeof(int) );
74  int i;
75 
76  for(i=0; i<param.iparm[IPARM_THREAD_NBR]; i++ ) {
77  bindtab[i] = param.iparm[IPARM_THREAD_NBR] * param.id + i;
78  }
79 
80  pastixInitWithAffinity( &pastix_data, MPI_COMM_WORLD,
81  param.iparm, param.dparm,
82  bindtab );
83  free( bindtab );
84  }
85 
86 #if defined(PASTIX_WITH_MPI)
87  {
88  int size, rank;
89  MPI_Comm_size( MPI_COMM_WORLD, &size );
90  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
91  if( size > 1 ) {
92  if ( rank == 0 ) {
93  fprintf( stderr, "\nWarning: Reentrant doesn't work with multiple MPI instances\n" );
94  fprintf( stderr, "Quitting now\n" );
95  }
96  pastixFinalize( &pastix_data );
97  exit(0);
98  }
99  }
100 #endif
101 
102  /**
103  * Read the sparse matrix with the driver
104  */
105  spm = malloc( sizeof( spmatrix_t ) );
106  if ( scatter ) {
107  rc = spmReadDriverDist( param.driver, param.filename, spm, MPI_COMM_WORLD );
108  }
109  else {
110  rc = spmReadDriver( param.driver, param.filename, spm );
111  }
112  if ( rc != SPM_SUCCESS ) {
113  pastixFinalize( &pastix_data );
114  return NULL;
115  }
116 
117  spmPrintInfo( spm, stdout );
118 
119  rc = spmCheckAndCorrect( spm, &spm2 );
120  if ( rc != 0 ) {
121  spmExit( spm );
122  *spm = spm2;
123  rc = 0;
124  }
125 
126  /**
127  * Generate a Fake values array if needed for the numerical part
128  */
129  if ( spm->flttype == SpmPattern ) {
130  spmGenFakeValues( spm );
131  }
132 
133  /**
134  * Perform ordering, symbolic factorization, and analyze steps
135  */
136  pastix_task_analyze( pastix_data, spm );
137 
138  /**
139  * Normalize A matrix (optional, but recommended for low-rank functionality)
140  */
141  double normA = spmNorm( SpmFrobeniusNorm, spm );
142  spmScal( 1./normA, spm );
143 
144  /**
145  * Perform the numerical factorization
146  */
147  pastix_task_numfact( pastix_data, spm );
148 
149  /**
150  * Generates the b and x vector such that A * x = b
151  * Compute the norms of the initial vectors if checking purpose.
152  */
153  size = pastix_size_of( spm->flttype ) * spm->nexp * nrhs;
154  x = malloc( size );
155  b = malloc( size );
156 
157  if ( check )
158  {
159  if ( check > 1 ) {
160  x0 = malloc( size );
161  }
162  spmGenRHS( SpmRhsRndX, nrhs, spm, x0, spm->nexp, b, spm->nexp );
163  memcpy( x, b, size );
164  }
165  else {
166  spmGenRHS( SpmRhsRndB, nrhs, spm, NULL, spm->nexp, x, spm->nexp );
167 
168  /* Apply also normalization to b vectors */
169  spmScalMat( 1./normA, spm, nrhs, b, spm->nexp );
170 
171  /* Save b for refinement */
172  memcpy( b, x, size );
173  }
174 
175  /**
176  * Solve the linear system (and perform the optional refinement)
177  */
178  pastix_task_solve( pastix_data, spm->nexp, nrhs, x, spm->nexp );
179  pastix_task_refine( pastix_data, spm->nexp, nrhs, b, spm->nexp, x, spm->nexp );
180 
181  if ( check )
182  {
183  param.rc = spmCheckAxb( param.dparm[DPARM_EPSILON_REFINEMENT], nrhs,
184  spm, x0, spm->nexp, b, spm->nexp, x, spm->nexp );
185 
186  if ( x0 ) {
187  free( x0 );
188  }
189  }
190 
191  spmExit( spm );
192  free( x );
193  free( b );
194  free( spm );
195  pastixFinalize( &pastix_data );
196 
197  return NULL;
198 }
199 
200 int main (int argc, char **argv)
201 {
202  pastix_int_t iparm[IPARM_SIZE]; /*< Integer in/out parameters for pastix */
203  double dparm[DPARM_SIZE]; /*< Floating in/out parameters for pastix */
204  spm_driver_t driver; /*< Matrix driver(s) requested by user */
205  char *filename = NULL; /*< Filename(s) given by user */
206  int nbcallingthreads = 2;
207  solve_param_t *solve_param;
208  pthread_t *threads;
209  int scatter = 0;
210  int check = 1;
211  int rc = 0;
212  int i;
213 
214  /**
215  * Initialize parameters to default values
216  */
217  pastixInitParam( iparm, dparm );
218 
219  /**
220  * Get options from command line
221  */
222  pastixGetOptions( argc, argv,
223  iparm, dparm,
224  &check, &scatter, &driver, &filename );
225 
226  /**
227  * Set parameters for each thread
228  */
229  solve_param = (solve_param_t*) malloc(nbcallingthreads * sizeof(solve_param_t));
230  threads = (pthread_t*) malloc(nbcallingthreads * sizeof(pthread_t));
231 
232  for (i = 0; i < nbcallingthreads; i++)
233  {
234  memcpy(solve_param[i].iparm, iparm, sizeof(solve_param[i].iparm));
235  memcpy(solve_param[i].dparm, dparm, sizeof(solve_param[i].dparm));
236  solve_param[i].check = check;
237  solve_param[i].scatter = scatter;
238  solve_param[i].id = i;
239  solve_param[i].driver = driver;
240  solve_param[i].filename = filename;
241  solve_param[i].rc = 0;
242 
243  /**
244  * Launch instance of solver
245  */
246  pthread_create(&threads[i], NULL, solve_smp, (void *)&solve_param[i]);
247  }
248 
249  /**
250  * Wait for the end of thread
251  */
252  for (i = 0; i < nbcallingthreads; i++) {
253  pthread_join(threads[i],(void**)NULL);
254  rc += solve_param[i].rc;
255  }
256 
257  free( filename );
258  free( threads );
259  free( solve_param );
260  return rc;
261 }
262 
263 /**
264  * @endcode
265  */
BEGIN_C_DECLS typedef int pastix_int_t
Definition: datatypes.h:51
void pastixFinalize(pastix_data_t **pastix_data)
Finalize the solver instance.
Definition: api.c:919
void pastixInitParam(pastix_int_t *iparm, double *dparm)
Initialize the iparm and dparm arrays to their default values.
Definition: api.c:411
void pastixInitWithAffinity(pastix_data_t **pastix_data, PASTIX_Comm pastix_comm, pastix_int_t *iparm, double *dparm, const int *bindtab)
Initialize the solver instance with a bintab array to specify the thread binding.
Definition: api.c:700
@ DPARM_EPSILON_REFINEMENT
Definition: api.h:161
@ IPARM_THREAD_NBR
Definition: api.h:118
void pastixGetOptions(int argc, char **argv, pastix_int_t *iparm, double *dparm, int *check, int *scatter, spm_driver_t *driver, char **filename)
PaStiX helper function to read command line options in examples.
Definition: get_options.c:149
pastix_int_t * iparm
Definition: pastixdata.h:69
int pastix_task_refine(pastix_data_t *pastix_data, pastix_int_t n, pastix_int_t nrhs, void *B, pastix_int_t ldb, void *X, pastix_int_t ldx)
Perform iterative refinement.
int pastix_task_analyze(pastix_data_t *pastix_data, const spmatrix_t *spm)
Perform all the preprocessing steps: ordering, symbolic factorization, reordering,...
int pastix_task_solve(pastix_data_t *pastix_data, pastix_int_t m, pastix_int_t nrhs, void *B, pastix_int_t ldb)
Solve the given problem.
int pastix_task_numfact(pastix_data_t *pastix_data, spmatrix_t *spm)
Perform all the numerical factorization steps: fill the internal block CSC and the solver matrix stru...
Main PaStiX data structure.
Definition: pastixdata.h:67