001: /* ///////////////////////////// P /// L /// A /// S /// M /// A /////////////////////////////// */
002: /* ///                    PLASMA auxiliary routines (version 2.1.0)                          ///
003:  * ///                    Author: Jakub Kurzak                                               ///
004:  * ///                    Release Date: November, 15th 2009                                  ///
005:  * ///                    PLASMA is a software package provided by Univ. of Tennessee,       ///
006:  * ///                    Univ. of California Berkeley and Univ. of Colorado Denver          /// */
007: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
008: #include "common.h"
009: #include "control.h"
010: #include "auxiliary.h"
011: #include "allocate.h"
012: 
013: #include <stdio.h>
014: #include <stdlib.h>
015: #if defined( _WIN32 ) || defined( _WIN64 )
016: #include "plasmawinthread.h"
017: #else
018: #include <pthread.h>
019: #endif
020: 
021: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
022: //  Busy-waiting barrier initialization
023: void plasma_barrier_init(plasma_context_t *plasma)
024: {
025:     int core;
026: 
027:     for (core = 0; core < CONTEXT_THREADS_MAX; core++) {
028:         plasma->barrier_in[core] = 0;
029:         plasma->barrier_out[core] = 0;
030:     }
031: }
032: 
033: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
034: //  Busy-waiting barrier
035: void plasma_barrier(plasma_context_t *plasma)
036: {
037:     int core;
038: 
039:     if (PLASMA_RANK == 0) {
040:         for (core = 1; core < PLASMA_SIZE; core++)
041:             while (plasma->barrier_in[core] == 0);
042: 
043:         for (core = 1; core < PLASMA_SIZE; core++)
044:             plasma->barrier_in[core] = 0;
045: 
046:         for (core = 1; core < PLASMA_SIZE; core++)
047:             plasma->barrier_out[core] = 1;
048:     }
049:     else
050:     {
051:         plasma->barrier_in[PLASMA_RANK] = 1;
052:         while (plasma->barrier_out[PLASMA_RANK] == 0);
053:         plasma->barrier_out[PLASMA_RANK] = 0;
054:     }
055: }
056: 
057: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
058: //  Main thread control
059: void *plasma_parallel_section(void *plasma_ptr)
060: {
061:     plasma_context_t *plasma = (plasma_context_t*)(plasma_ptr);
062:     PLASMA_enum action;
063: 
064:     plasma_barrier(plasma);
065:     while(1) {
066:         pthread_mutex_lock(&plasma->action_mutex);
067:         while ((action = plasma->action) == PLASMA_ACT_STAND_BY)
068:             pthread_cond_wait(&plasma->action_condt, &plasma->action_mutex);
069:         pthread_mutex_unlock(&plasma->action_mutex);
070:         plasma_barrier(plasma);
071: 
072:         switch (action) {
073:             case PLASMA_ACT_PARALLEL:
074:                 plasma->parallel_func_ptr(plasma);
075:                 break;
076:             case PLASMA_ACT_FINALIZE:
077:                 return NULL;
078:             default:
079:                 plasma_fatal_error("plasma_parallel_section", "undefined action");
080:                 return NULL;
081:         }
082:         plasma_barrier(plasma);
083:     }
084:     return NULL;
085: }
086: 
087: /* /////////////////////////// P /// U /// R /// P /// O /// S /// E /////////////////////////// */
088: // PLASMA_Init - Initialize PLASMA.
089: 
090: /* ///////////////////// A /// R /// G /// U /// M /// E /// N /// T /// S ///////////////////// */
091: // cores    int (IN)
092: //          Number of cores to use (threads to launch)
093: 
094: /* ///////////// R /// E /// T /// U /// R /// N /////// V /// A /// L /// U /// E ///////////// */
095: //          = PLASMA_SUCCESS: successful exit
096: 
097: /* //////////////////////////////////// C /// O /// D /// E //////////////////////////////////// */
098: int PLASMA_Init(int cores)
099: {
100:     plasma_context_t *plasma;
101:     int status;
102:     int core;
103: 
104:     /* IF already initialized
105:        finalize and re-initialize */
106: 
107:     /* Create context and insert in the context map */
108:     plasma = plasma_context_create();
109:     if (plasma == NULL) {
110:         plasma_fatal_error("PLASMA_Init", "plasma_context_create() failed");
111:         return PLASMA_ERR_OUT_OF_RESOURCES;
112:     }
113:     status = plasma_context_insert(plasma, pthread_self());
114:     if (status != PLASMA_SUCCESS) {
115:         plasma_fatal_error("PLASMA_Init", "plasma_context_insert() failed");
116:         return PLASMA_ERR_OUT_OF_RESOURCES;
117:     }
118:     /* Set number of cores */
119:     plasma->world_size = cores;
120: //  plasma->world_size = sysconf(_SC_NPROCESSORS_ONLN);
121:     if (plasma->world_size <= 0) {
122:         plasma_fatal_error("PLASMA_Init", "failed to get system size");
123:         return PLASMA_ERR_NOT_FOUND;
124:     }
125:     /* Check if not more cores than the hard limit */
126:     if (plasma->world_size > CONTEXT_THREADS_MAX) {
127:         plasma_fatal_error("PLASMA_Init", "not supporting so many cores");
128:         return PLASMA_ERR_INTERNAL_LIMIT;
129:     }
130: 
131:     /* Initialize barrier */
132:     plasma_barrier_init(plasma);
133: 
134:     /* Initialize default thread attributes */
135:     status = pthread_attr_init(&plasma->thread_attr);
136:     if (status != 0) {
137:         plasma_fatal_error("PLASMA_Init", "pthread_attr_init() failed");
138:         return status;
139:     }
140:     /* Set scope to system */
141:     status = pthread_attr_setscope(&plasma->thread_attr, PTHREAD_SCOPE_SYSTEM);
142:     if (status != 0) {
143:         plasma_fatal_error("PLASMA_Init", "pthread_attr_setscope() failed");
144:         return status;
145:     }
146:     /* Set concurrency */
147:     status = pthread_setconcurrency(plasma->world_size);
148:     if (status != 0) {
149:         plasma_fatal_error("PLASMA_Init", "pthread_setconcurrency() failed");
150:         return status;
151:     }
152:     /*  Launch threads */
153:     for (core = 1; core < plasma->world_size; core++) {
154:         plasma->thread_rank[core] = core;
155:         pthread_create(
156:             &plasma->thread_id[core],
157:             &plasma->thread_attr,
158:              plasma_parallel_section,
159:              (void*)plasma);
160:     }
161:     plasma->thread_rank[0] = 0;
162:     plasma->thread_id[0] = pthread_self();
163: 
164:     plasma_barrier(plasma);
165:     return PLASMA_SUCCESS;
166: }
167: 
168: /* /////////////////////////// P /// U /// R /// P /// O /// S /// E /////////////////////////// */
169: // PLASMA_Finalize - Finalize PLASMA.
170: 
171: /* ///////////////////// A /// R /// G /// U /// M /// E /// N /// T /// S ///////////////////// */
172: 
173: /* ///////////// R /// E /// T /// U /// R /// N /////// V /// A /// L /// U /// E ///////////// */
174: //          = PLASMA_SUCCESS: successful exit
175: 
176: /* //////////////////////////////////// C /// O /// D /// E //////////////////////////////////// */
177: int PLASMA_Finalize()
178: {
179:     int core;
180:     int status;
181:     void *exitcodep;
182:     plasma_context_t *plasma;
183: 
184:     plasma = plasma_context_self();
185:     if (plasma == NULL) {
186:         plasma_fatal_error("PLASMA_Finalize()", "PLASMA not initialized");
187:         return PLASMA_ERR_NOT_INITIALIZED;
188:     }
189:     /* Set termination action */
190:     pthread_mutex_lock(&plasma->action_mutex);
191:     plasma->action = PLASMA_ACT_FINALIZE;
192:     pthread_mutex_unlock(&plasma->action_mutex);
193:     pthread_cond_broadcast(&plasma->action_condt);
194: 
195:     /* Barrier and clear action */
196:     plasma_barrier(plasma);
197:     plasma->action = PLASMA_ACT_STAND_BY;
198: 
199:     // Join threads
200:     for (core = 1; core < plasma->world_size; core++) {
201:         status = pthread_join(plasma->thread_id[core], &exitcodep);
202:         if (status != 0) {
203:             plasma_fatal_error("PLASMA_Finalize", "pthread_join() failed");
204:             return status;
205:         }
206:     }
207:     /* Destroy thread attributes */
208:     status = pthread_attr_destroy(&plasma->thread_attr);
209:     if (status != 0)
210:         plasma_fatal_error("PLASMA_Finalize", "pthread_attr_destroy() failed");
211: 
212:     status = plasma_context_remove(plasma, pthread_self());
213:     if (status != PLASMA_SUCCESS) {
214:         plasma_fatal_error("PLASMA_Finalize", "plasma_context_remove() failed");
215:         return status;
216:     }
217:     return PLASMA_SUCCESS;
218: }
219: