1 //------------------------------------------------------------------------------
2 // GraphBLAS/Demo/Program/openmp_demo: example of user multithreading
3 //------------------------------------------------------------------------------
4 
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7 
8 //------------------------------------------------------------------------------
9 
10 // This demo uses OpenMP, and illustrates how GraphBLAS can be called from
11 // a multi-threaded user program.
12 
13 #include "GraphBLAS.h"
14 
15 #ifdef _OPENMP
16 #include <omp.h>
17 #endif
18 
19 #if defined __INTEL_COMPILER
20 #pragma warning (disable: 58 167 144 177 181 186 188 589 593 869 981 1418 1419 1572 1599 2259 2282 2557 2547 3280 )
21 #elif defined __GNUC__
22 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
23 #pragma GCC diagnostic ignored "-Wunused-parameter"
24 #if !defined ( __cplusplus )
25 #pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
26 #endif
27 #endif
28 
29 #define NTHREADS 8
30 #define NTRIALS 10
31 #define N 6
32 
33 #define OK(method)                                                  \
34 {                                                                   \
35     GrB_Info info = method ;                                        \
36     if (! (info == GrB_SUCCESS || info == GrB_NO_VALUE))            \
37     {                                                               \
38         printf ("Failure (id: %d, info: %d):\n", id, info) ;        \
39         /* return to caller (do not use inside critical section) */ \
40         return (0) ;                                                \
41     }                                                               \
42 }
43 
44 //------------------------------------------------------------------------------
45 // worker
46 //------------------------------------------------------------------------------
47 
worker(GrB_Matrix * Ahandle,int id)48 int worker (GrB_Matrix *Ahandle, int id)
49 {
50 
51     printf ("\n================= worker %d starts:\n", id) ;
52     fprintf (stderr, "worker %d\n", id) ;
53 
54     OK (GrB_Matrix_new (Ahandle, GrB_FP64, N, N)) ;
55     GrB_Matrix A = *Ahandle ;
56 
57     // worker generates an intentional error message
58     GrB_Matrix_setElement_INT32 (A, 42, 1000+id, 1000+id) ;
59 
60     // print the intentional error generated when the worker started
61     #pragma omp critical
62     {
63         // critical section
64         printf ("\n----------------- worker %d intentional error:\n", id) ;
65         const char *s ;
66         GrB_Matrix_error (&s, A) ;
67         printf ("%s\n", s) ;
68     }
69 
70     for (int hammer_hard = 0 ; hammer_hard < NTRIALS ; hammer_hard++)
71     {
72         for (int i = 0 ; i < N ; i++)
73         {
74             for (int j = 0 ; j < N ; j++)
75             {
76                 double x = (i+1)*100000 + (j+1)*1000 + id ;
77                 OK (GrB_Matrix_setElement_FP64 (A, x, i, j)) ;
78             }
79         }
80 
81         // force completion
82         OK (GrB_Matrix_wait (&A)) ;
83     }
84 
85     // Printing is done in a critical section, just so it is not overly
86     // jumbled.  Each matrix and error will print in a single body of text,
87     // but the order of the matrices and errors printed will be out of order
88     // because the critical section does not enforce the order that the
89     // threads enter.
90 
91     GrB_Info info2 ;
92     #pragma omp critical
93     {
94         // critical section
95         printf ("\n----------------- worker %d is done:\n", id) ;
96         info2 = GxB_Matrix_fprint (A, "A", GxB_SHORT, stdout) ;
97     }
98     OK (info2) ;
99 
100     // worker generates an intentional error message
101     GrB_Matrix_setElement_INT32 (A, 42, 1000+id, 1000+id) ;
102 
103     // print the intentional error generated when the worker started
104     // It should be unchanged.
105     #pragma omp critical
106     {
107         // critical section
108         printf ("\n----------------- worker %d error should be same:\n", id) ;
109         const char *s ;
110         GrB_Matrix_error (&s, A) ;
111         printf ("%s\n", s) ;
112     }
113     return (0) ;
114 }
115 
116 //------------------------------------------------------------------------------
117 // openmp_demo main program
118 //------------------------------------------------------------------------------
119 
main(int argc,char ** argv)120 int main (int argc, char **argv)
121 {
122     fprintf (stderr, "Demo: %s:\n", argv [0]) ;
123     printf ("Demo: %s:\n", argv [0]) ;
124 
125     // initialize the mutex
126     int id = -1 ;
127 
128     // start GraphBLAS
129     OK (GrB_init (GrB_NONBLOCKING)) ;
130     int nthreads ;
131     OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ;
132     fprintf (stderr, "openmp demo, nthreads %d\n", nthreads) ;
133 
134     // Determine which user-threading model is being used.
135     #ifdef _OPENMP
136     printf ("User threads in this program are OpenMP threads.\n") ;
137     #else
138     printf ("This user program is single threaded.\n") ;
139     #endif
140 
141     GrB_Matrix Aarray [NTHREADS] ;
142 
143     // create the threads
144     #pragma omp parallel for num_threads(NTHREADS)
145     for (id = 0 ; id < NTHREADS ; id++)
146     {
147         worker (&Aarray [id], id) ;
148     }
149 
150     // the leader thread prints them again, and frees them
151     for (int id = 0 ; id < NTHREADS ; id++)
152     {
153         GrB_Matrix A = Aarray [id] ;
154         printf ("\n---- Leader prints matrix %d\n", id) ;
155         OK (GxB_Matrix_fprint (A, "A", GxB_SHORT, stdout)) ;
156         GrB_Matrix_free (&A) ;
157     }
158 
159     // finish GraphBLAS
160     GrB_finalize ( ) ;
161 
162     // finish OpenMP
163     exit (0) ;
164 }
165 
166