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 "auxiliary.h"
010: #include "context.h"
011: 
012: #if defined( _WIN32 ) || defined( _WIN64 )
013: #include "plasmawinthread.h"
014: #else
015: #include <pthread.h>
016: #endif
017: 
018: #include <stdlib.h>
019: 
020: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
021: //  Global data
022: // master threads context lookup table
023: plasma_context_map_t context_map[CONTEXTS_MAX];
024: // context lookup table access lock
025: pthread_mutex_t context_map_lock = PTHREAD_MUTEX_INITIALIZER;
026: 
027: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
028: // Create new context
029: plasma_context_t *plasma_context_create()
030: {
031:     plasma_context_t *plasma;
032: 
033:     plasma = (plasma_context_t*)malloc(sizeof(plasma_context_t));
034:     if (plasma == NULL) {
035:         plasma_fatal_error("plasma_context_create", "malloc() failed");
036:         return NULL;
037:     }
038: 
039:     pthread_mutex_init(&plasma->action_mutex, NULL);
040:     pthread_mutex_init(&context_map_lock, NULL);
041:     pthread_cond_init(&plasma->action_condt, NULL);
042:     plasma->action = PLASMA_ACT_STAND_BY;
043:     plasma->parallel_func_ptr = NULL;
044: 
045:     /* These initializations are just in case the user
046:        disables autotuning and does not set nb and ib */
047:     plasma->nb = 128;
048:     plasma->ib = 32;
049:     plasma->nbnbsize = 16384;
050:     plasma->ibnbsize = 4096;
051:     plasma->info = 0;
052: 
053:     plasma->errors_enabled     = PLASMA_FALSE;
054:     plasma->warnings_enabled   = PLASMA_FALSE;
055:     plasma->autotuning_enabled = PLASMA_TRUE;
056: 
057:     return plasma;
058: }
059: 
060: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
061: // Insert a (context, thread_id) tuple in the context map
062: int plasma_context_insert(plasma_context_t *context, pthread_t thread_id)
063: {
064:     int i;
065: 
066:     // acquire the access lock
067:     pthread_mutex_lock(&context_map_lock);
068:     // For each entry
069:     for (i = 0; i < CONTEXTS_MAX; i++) {
070:         // If not occupied
071:         if (context_map[i].context == NULL) {
072:             // Insert new context, release lock, return success
073:             context_map[i].context = context;
074:             context_map[i].thread_id = thread_id;
075:             pthread_mutex_unlock(&context_map_lock);
076:             return PLASMA_SUCCESS;
077:         }
078:     }
079:     // No empty entry found - release lock, return error
080:     pthread_mutex_unlock(&context_map_lock);
081:     plasma_fatal_error("plasma_context_insert", "too many threads");
082:     return PLASMA_ERR_INTERNAL_LIMIT;
083: }
084: 
085: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
086: // Remove a (context, thread_id) tuple from the context map
087: int plasma_context_remove(plasma_context_t *context, pthread_t thread_id)
088: {
089:     int i;
090: 
091:     // acquire the access lock
092:     pthread_mutex_lock(&context_map_lock);
093:     // For each entry
094:     for (i = 0; i < CONTEXTS_MAX; i++) {
095:         // If id matches
096:         if (pthread_equal(context_map[i].thread_id, thread_id)) {
097:             if (context_map[i].context == context) {
098:                 // Free the context, mark entry as empty, release lock, return success
099:                 free(context_map[i].context);
100:                 context_map[i].context = NULL;
101:                 pthread_mutex_unlock(&context_map_lock);
102:                 return PLASMA_SUCCESS;
103:             }
104:             else {
105:                 pthread_mutex_unlock(&context_map_lock);
106:                 plasma_fatal_error("plasma_context_remove", "context does not match thread");
107:                 return PLASMA_ERR_UNEXPECTED;
108:             }
109:         }
110:     }
111:     // No matching id found - release lock, return error
112:     pthread_mutex_unlock(&context_map_lock);
113:     plasma_fatal_error("plasma_context_remove", "thread not found");
114:     return PLASMA_ERR_NOT_FOUND;
115: }
116: 
117: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
118: // Return context for a thread
119: plasma_context_t *plasma_context_self()
120: {
121:     int i;
122: 
123:     // For each entry
124:     for (i = 0; i < CONTEXTS_MAX; i++) {
125:         // If id matches
126:         if (pthread_equal(context_map[i].thread_id, pthread_self())) {
127:             return context_map[i].context;
128:         }
129:     }
130:     return NULL;
131: }
132: 
133: /* /////////////////////////// P /// U /// R /// P /// O /// S /// E /////////////////////////// */
134: // PLASMA_Enable - Enable PLASMA feature.
135: 
136: /* ///////////////////// A /// R /// G /// U /// M /// E /// N /// T /// S ///////////////////// */
137: // lever    PLASMA_enum (IN)
138: //          Feature to be enabled:
139: //          = PLASMA_WARNINGS:   printing of warning messages,
140: //          = PLASMA_ERRORS:     printing of error messages,
141: //          = PLASMA_AUTOTUNING: autotuning for tile size and inner block size.
142: 
143: /* ///////////// R /// E /// T /// U /// R /// N /////// V /// A /// L /// U /// E ///////////// */
144: //          = PLASMA_SUCCESS: successful exit
145: 
146: /* //////////////////////////////////// C /// O /// D /// E //////////////////////////////////// */
147: int PLASMA_Enable(PLASMA_enum lever)
148: {
149:     plasma_context_t *plasma;
150: 
151:     plasma = plasma_context_self();
152:     if (plasma == NULL) {
153:         plasma_fatal_error("PLASMA_Enable", "PLASMA not initialized");
154:         return PLASMA_ERR_NOT_INITIALIZED;
155:     }
156: 
157:     switch (lever)
158:     {
159:         case PLASMA_WARNINGS:
160:             plasma->warnings_enabled = PLASMA_TRUE;
161:             break;
162:         case PLASMA_ERRORS:
163:             plasma->errors_enabled = PLASMA_TRUE;
164:             break;
165:         case PLASMA_AUTOTUNING:
166:             plasma->autotuning_enabled = PLASMA_TRUE;
167:             break;
168:         default:
169:             plasma_error("PLASMA_Enable", "illegal parameter value");
170:             return PLASMA_ERR_ILLEGAL_VALUE;
171:     }
172:     return PLASMA_SUCCESS;
173: }
174: 
175: /* /////////////////////////// P /// U /// R /// P /// O /// S /// E /////////////////////////// */
176: // PLASMA_Disable - Disable PLASMA feature.
177: 
178: /* ///////////////////// A /// R /// G /// U /// M /// E /// N /// T /// S ///////////////////// */
179: // lever    PLASMA_enum (IN)
180: //          Feature to be disabled:
181: //          = PLASMA_WARNINGS:   printing of warning messages,
182: //          = PLASMA_ERRORS:     printing of error messages,
183: //          = PLASMA_AUTOTUNING: autotuning for tile size and inner block size.
184: 
185: /* ///////////// R /// E /// T /// U /// R /// N /////// V /// A /// L /// U /// E ///////////// */
186: //          = PLASMA_SUCCESS: successful exit
187: 
188: /* //////////////////////////////////// C /// O /// D /// E //////////////////////////////////// */
189: int PLASMA_Disable(PLASMA_enum lever)
190: {
191:     plasma_context_t *plasma;
192: 
193:     plasma = plasma_context_self();
194:     if (plasma == NULL) {
195:         plasma_fatal_error("PLASMA_Disable", "PLASMA not initialized");
196:         return PLASMA_ERR_NOT_INITIALIZED;
197:     }
198:     switch (lever)
199:     {
200:         case PLASMA_WARNINGS:
201:             plasma->warnings_enabled = PLASMA_FALSE;
202:             break;
203:         case PLASMA_ERRORS:
204:             plasma->errors_enabled = PLASMA_FALSE;
205:             break;
206:         case PLASMA_AUTOTUNING:
207:             plasma->autotuning_enabled = PLASMA_FALSE;
208:             break;
209:         default:
210:             plasma_error("PLASMA_Disable", "illegal parameter value");
211:             return PLASMA_ERR_ILLEGAL_VALUE;
212:     }
213:     return PLASMA_SUCCESS;
214: }
215: 
216: /* /////////////////////////// P /// U /// R /// P /// O /// S /// E /////////////////////////// */
217: // PLASMA_Set - Set PLASMA parameter
218: 
219: /* ///////////////////// A /// R /// G /// U /// M /// E /// N /// T /// S ///////////////////// */
220: // param    PLASMA_enum (IN)
221: //          PLASMA parameter:
222: //          = PLASMA_TILE_SIZE:        size matrix tile,
223: //          = PLASMA_INNER_BLOCK_SIZE: size of tile inner block.
224: //
225: // value    int (IN)
226: //          Value of the parameter.
227: 
228: /* ///////////// R /// E /// T /// U /// R /// N /////// V /// A /// L /// U /// E ///////////// */
229: //          = PLASMA_SUCCESS: successful exit
230: 
231: /* //////////////////////////////////// C /// O /// D /// E //////////////////////////////////// */
232: int PLASMA_Set(PLASMA_enum param, int value)
233: {
234:     plasma_context_t *plasma;
235: 
236:     plasma = plasma_context_self();
237:     if (plasma == NULL) {
238:         plasma_error("PLASMA_Set", "PLASMA not initialized");
239:         return PLASMA_ERR_NOT_INITIALIZED;
240:     }
241:     switch (param) {
242:         case PLASMA_TILE_SIZE:
243:             if (value <= 0) {
244:                 plasma_error("PLASMA_Set", "negative tile size");
245:                 return PLASMA_ERR_ILLEGAL_VALUE;
246:             }
247:             plasma->nb = value;
248:             /* Calculate A, B tile size and round up to cache line size */
249:             /* round up for the smallest type (float) - will hold for all */
250:             plasma->nbnbsize = plasma->nb * plasma->nb; // * sizeof(float);
251: //          plasma->nbnbsize = roundup(plasma->nbnbsize, CACHE_LINE_SIZE);
252: //          plasma->nbnbsize /= sizeof(float);
253:             break;
254:         case PLASMA_INNER_BLOCK_SIZE:
255:             if (value <= 0) {
256:                 plasma_error("PLASMA_Set", "negative inner block size");
257:                 return PLASMA_ERR_ILLEGAL_VALUE;
258:             }
259:             if (value > plasma->nb) {
260:                 plasma_error("PLASMA_Set", "inner block larger than tile");
261:                 return PLASMA_ERR_ILLEGAL_VALUE;
262:             }
263:             if (plasma->nb % value != 0) {
264:                 plasma_error("PLASMA_Set", "inner block does not divide tile");
265:                 return PLASMA_ERR_ILLEGAL_VALUE;
266:             }
267:             plasma->ib = value;
268:             /* Calculate T, L tile size and round up to cache line size */
269:             /* round up for the smallest type (float) - will hold for all */
270:             plasma->ibnbsize = plasma->ib * plasma->nb; // * sizeof(float);
271: //          plasma->ibnbsize = roundup(plasma->ibnbsize, CACHE_LINE_SIZE);
272: //          plasma->ibnbsize /= sizeof(float);
273:             break;
274:         default:
275:             plasma_error("PLASMA_Set", "unknown parameter");
276:             return PLASMA_ERR_ILLEGAL_VALUE;
277:     }
278:     return PLASMA_SUCCESS;
279: }
280: 
281: /* /////////////////////////// P /// U /// R /// P /// O /// S /// E /////////////////////////// */
282: // PLASMA_Get - Get value of PLASMA parameter
283: 
284: /* ///////////////////// A /// R /// G /// U /// M /// E /// N /// T /// S ///////////////////// */
285: // param    PLASMA_enum (IN)
286: //          PLASMA parameter:
287: //          = PLASMA_TILE_SIZE:        size matrix tile,
288: //          = PLASMA_INNER_BLOCK_SIZE: size of tile inner block.
289: //
290: // value    int* (OUT)
291: //          Value of the parameter.
292: 
293: /* ///////////// R /// E /// T /// U /// R /// N /////// V /// A /// L /// U /// E ///////////// */
294: //          = PLASMA_SUCCESS: successful exit
295: 
296: /* //////////////////////////////////// C /// O /// D /// E //////////////////////////////////// */
297: int PLASMA_Get(PLASMA_enum param, int *value)
298: {
299:     plasma_context_t *plasma;
300: 
301:     plasma = plasma_context_self();
302:     if (plasma == NULL) {
303:         plasma_fatal_error("PLASMA_Get", "PLASMA not initialized");
304:         return PLASMA_ERR_NOT_INITIALIZED;
305:     }
306:     switch (param) {
307:         case PLASMA_TILE_SIZE:
308:             *value = plasma->nb;
309:             return PLASMA_SUCCESS;
310:         case PLASMA_INNER_BLOCK_SIZE:
311:             *value = plasma->ib;
312:             return PLASMA_SUCCESS;
313:         default:
314:             plasma_error("PLASMA_Get", "unknown parameter");
315:             return PLASMA_ERR_ILLEGAL_VALUE;
316:     }
317: }
318: