PaStiX Handbook 6.4.0
Loading...
Searching...
No Matches
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-2025 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
7 * Univ. Bordeaux. All rights reserved.
8 *
9 * @version 6.4.0
10 * @author Mathieu Faverge
11 * @author Matias Hastaran
12 * @author Pierre Ramet
13 * @author Tony Delarue
14 * @author Alycia Lisito
15 * @date 2024-07-05
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 */
31typedef 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 */
50static 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
200int 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:928
void pastixInitParam(pastix_int_t *iparm, double *dparm)
Initialize the iparm and dparm arrays to their default values.
Definition api.c:420
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:709
@ 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.
pastix_int_t * iparm
Definition pastixdata.h:70
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:68