PLASMA  2.4.5
PLASMA - Parallel Linear Algebra for Scalable Multi-core Architectures
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
plasmaos.c
Go to the documentation of this file.
1 
16 #if defined(linux) || defined(__linux) || defined(__linux__)
17 #define PLASMA_OS_LINUX 1
18 #define _GNU_SOURCE
19 #include <unistd.h>
20 #include <sched.h>
21 #elif defined( _WIN32 ) || defined( _WIN64 )
22 #define PLASMA_OS_WINDOWS 1
23 #include <Windows.h>
24 #elif (defined __APPLE__) || (defined macintosh) || (defined __MACOSX__)
25 #define PLASMA_OS_MACOS 1
26 #include <sys/param.h>
27 #include <sys/sysctl.h>
28 #include <mach/mach_init.h>
29 #include <mach/thread_policy.h>
30 kern_return_t thread_policy_set(thread_act_t thread, thread_policy_flavor_t flavor,
31  thread_policy_t policy_info, mach_msg_type_number_t count);
32 #elif (defined _AIX)
33 #define PLASMA_OS_AIX 1
34 #else
35 #error "Cannot find the runing system or system not supported. Please define try to PLASMA_OS_[LINUX|MACOS|AIX|WINDOWS]"
36 #endif
37 
38 #if defined(PLASMA_HWLOC) && (defined PLASMA_AFFINITY_DISABLE)
39 #undef PLASMA_HWLOC
40 #endif
41 
42 #include <errno.h>
43 #include <stdlib.h>
44 #include "common.h"
45 
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 
51 static volatile int sys_corenbr = 1;
52 static volatile int topo_initialized = 0;
53 
54  /*
55  * Topology functions
56  */
57 #ifdef PLASMA_HWLOC
58 #include "plasmaos-hwloc.c"
59 #else
60 
62  pthread_mutex_lock(&mutextopo);
63  if ( !topo_initialized ) {
64 #if (defined PLASMA_OS_LINUX) || (defined PLASMA_OS_AIX)
65 
66  sys_corenbr = sysconf(_SC_NPROCESSORS_ONLN);
67 
68 #elif (defined PLASMA_OS_MACOS)
69 
70  int mib[4];
71  int cpu;
72  size_t len = sizeof(cpu);
73 
74  /* set the mib for hw.ncpu */
75  mib[0] = CTL_HW;
76  mib[1] = HW_AVAILCPU;
77 
78  /* get the number of CPUs from the system */
79  sysctl(mib, 2, &cpu, &len, NULL, 0);
80  if( cpu < 1 ) {
81  mib[1] = HW_NCPU;
82  sysctl( mib, 2, &cpu, &len, NULL, 0 );
83  }
84  if( cpu < 1 ) {
85  cpu = 1;
86  }
87  sys_corenbr = cpu;
88 #elif (defined PLASMA_OS_WINDOWS)
89  SYSTEM_INFO sysinfo;
90  GetSystemInfo(&sysinfo);
91  sys_corenbr = sysinfo.dwNumberOfProcessors;
92 #endif
93  }
94  pthread_mutex_unlock(&mutextopo);
95 }
96 
99 }
100 
110 int plasma_setaffinity(int rank) {
111 #ifndef PLASMA_AFFINITY_DISABLE
112 #if (defined PLASMA_OS_LINUX)
113  {
114  cpu_set_t set;
115  CPU_ZERO( &set );
116  CPU_SET( rank, &set );
117 
118 #if (defined HAVE_OLD_SCHED_SETAFFINITY)
119  if( sched_setaffinity( 0, &set ) < 0 )
120 #else /* HAVE_OLD_SCHED_SETAFFINITY */
121  if( sched_setaffinity( 0, sizeof(set), &set) < 0 )
122 #endif /* HAVE_OLD_SCHED_SETAFFINITY */
123  {
124  return PLASMA_ERR_UNEXPECTED;
125  }
126 
127  return PLASMA_SUCCESS;
128  }
129 #elif (defined PLASMA_OS_MACOS)
130  {
131  thread_affinity_policy_data_t ap;
132  int ret;
133 
134  ap.affinity_tag = 1; /* non-null affinity tag */
135  ret = thread_policy_set( mach_thread_self(),
136  THREAD_AFFINITY_POLICY,
137  (integer_t*) &ap,
138  THREAD_AFFINITY_POLICY_COUNT
139  );
140  if(ret != 0)
141  return PLASMA_ERR_UNEXPECTED;
142 
143  return PLASMA_SUCCESS;
144  }
145 #elif (defined PLASMA_OS_WINDOWS)
146  {
147  DWORD mask = 1 << rank;
148 
149  if( SetThreadAffinityMask(GetCurrentThread(), mask) == 0)
150  return PLASMA_ERR_UNEXPECTED;
151 
152  return PLASMA_SUCCESS;
153  }
154 #elif (defined PLASMA_OS_AIX)
155  {
156  tid_t self_ktid = thread_self ();
157  bindprocessor(BINDTHREAD, self_ktid, rank);
158  return PLASMA_SUCCESS;
159  }
160 #else
162 #endif
163 #endif /* PLASMA_AFFINITY_DISABLE */
164 }
165 
175 int plasma_unsetaffinity(int rank) {
176 #ifndef PLASMA_AFFINITY_DISABLE
177 #if (defined PLASMA_OS_LINUX)
178  {
179  int i;
180  cpu_set_t set;
181  CPU_ZERO( &set );
182 
183  for(i=0; i<sys_corenbr; i++)
184  CPU_SET( i, &set );
185 
186 #if (defined HAVE_OLD_SCHED_SETAFFINITY)
187  if( sched_setaffinity( 0, &set ) < 0 )
188 #else /* HAVE_OLD_SCHED_SETAFFINITY */
189  if( sched_setaffinity( 0, sizeof(set), &set) < 0 )
190 #endif /* HAVE_OLD_SCHED_SETAFFINITY */
191  {
192  plasma_warning("plasma_unsetaffinity", "Could not unbind thread");
193  return PLASMA_ERR_UNEXPECTED;
194  }
195 
196  return PLASMA_SUCCESS;
197  }
198 #elif (defined PLASMA_OS_MACOS)
199  {
200  /* TODO: check how to unbind the main thread if necessary for OpenMP */
201  /* thread_affinity_policy_data_t ap; */
202  /* int ret; */
203 
204  /* ap.affinity_tag = 1; /\* non-null affinity tag *\/ */
205  /* ret = thread_policy_set( mach_thread_self(), */
206  /* THREAD_AFFINITY_POLICY, */
207  /* (integer_t*) &ap, */
208  /* THREAD_AFFINITY_POLICY_COUNT */
209  /* ); */
210  /* if(ret != 0) { */
211  /* plasma_warning("plasma_unsetaffinity", "Could not unbind thread"); */
212  /* return PLASMA_ERR_UNEXPECTED; */
213  /* } */
214 
215  return PLASMA_SUCCESS;
216  }
217 #elif (defined PLASMA_OS_WINDOWS)
218  {
219  DWORD mask = 0;
220 
221  for(i=0; i<sys_corenbr; i++)
222  mask |= 1 << i;
223 
224  if( SetThreadAffinityMask(GetCurrentThread(), mask) == 0) {
225  plasma_warning("plasma_unsetaffinity", "Could not unbind thread");
226  return PLASMA_ERR_UNEXPECTED;
227  }
228  return PLASMA_SUCCESS;
229  }
230 #elif (defined PLASMA_OS_AIX)
231  {
232  /* TODO: check how to unbind the main thread if necessary for OpenMP */
233  /* tid_t self_ktid = thread_self (); */
234  /* bindprocessor(BINDTHREAD, self_ktid, rank); */
235  return PLASMA_SUCCESS;
236  }
237 #else
239 #endif
240 #endif /* PLASMA_AFFINITY_DISABLE */
241 }
242 #endif /* PLASMA_HWLOC */
243 
249 #if (defined PLASMA_OS_LINUX) || (defined PLASMA_OS_MACOS) || (defined PLASMA_OS_AIX)
250  return sched_yield();
251 #elif PLASMA_OS_WINDOWS
252  return SleepEx(0,0);
253 #else
255 #endif
256 }
257 
258 #ifdef PLASMA_OS_WINDOWS
259 #define PLASMA_GETENV(var, str) { \
260  int len = 512; \
261  int ret; \
262  str = (char*)malloc(len * sizeof(char)); \
263  ret = GetEnvironmentVariable(var, str, len); \
264  if (ret == 0) { \
265  free(str); \
266  str = NULL; \
267  } \
268  }
269 
270 #define PLASMA_CLEANENV(str) if (str != NULL) free(str);
271 
272 #else /* Other OS systems */
273 
274 #define PLASMA_GETENV(var, str) envstr = getenv(var);
275 #define PLASMA_CLEANENV(str)
276 
277 #endif
278 
284 {
285  char *envstr = NULL;
286  char *endptr;
287  long int thrdnbr = -1;
288  extern int errno;
289 
290  /* Env variable does not exist, we search the system number of core */
291  PLASMA_GETENV("PLASMA_NUM_THREADS", envstr);
292  if ( envstr == NULL ) {
293  thrdnbr = sys_corenbr;
294  } else {
295  /* Convert to long, checking for errors */
296  thrdnbr = strtol(envstr, &endptr, 10);
297  if ((errno == ERANGE) || ((thrdnbr==0) && (endptr==envstr))) {
298  PLASMA_CLEANENV(envstr);
299  return -1;
300  }
301  }
302  PLASMA_CLEANENV(envstr);
303  return (int)thrdnbr;
304 }
305 
307 {
308  char *envstr = NULL;
309  char *endptr;
310  long int thrdnbr = -1;
311  extern int errno;
312 
313  /* Env variable does not exist, we search the system number of core */
314  PLASMA_GETENV("PLASMA_NUM_THREADS_NUMA", envstr);
315  if ( envstr != NULL ) {
316  /* Convert to long, checking for errors */
317  thrdnbr = strtol(envstr, &endptr, 10);
318  if ((errno == ERANGE) || ((thrdnbr==0) && (endptr==envstr))) {
319  PLASMA_CLEANENV(envstr);
320  return -1;
321  }
322  } else {
323 #ifdef PLASMA_HWLOC
324  thrdnbr = plasma_getnuma_size();
325 #else
326  thrdnbr = 1;
327 #endif
328  }
329 
330  PLASMA_CLEANENV(envstr);
331  return (int)thrdnbr;
332 }
333 
334 int plasma_get_affthreads(int *coresbind) {
335  char *envstr = NULL;
336  int i;
337 
338  /* Env variable does not exist, we search the system number of core */
339  PLASMA_GETENV("PLASMA_AFF_THREADS", envstr);
340  if ( envstr == NULL) {
341  for (i = 0; i < CONTEXT_THREADS_MAX; i++)
342  coresbind[i] = i % sys_corenbr;
343  }
344  else {
345  char *endptr;
346  int wrap = 0;
347  int nbr = 0;
348  long int val;
349 
350  /* We use the content of the PLASMA_AFF_THREADS env. variable */
351  for (i = 0; i < CONTEXT_THREADS_MAX; i++) {
352  if (!wrap) {
353  val = strtol(envstr, &endptr, 10);
354  if (endptr != envstr) {
355  coresbind[i] = (int)val;
356  envstr = endptr;
357  }
358  else {
359  /* there must be at least one entry */
360  if (i < 1) {
361  plasma_error("plasma_get_affthreads", "PLASMA_AFF_THREADS should have at least one entry => everything will be bind on core 0");
362  coresbind[i] = 0;
363  i++;
364  }
365 
366  /* there is no more values in the string */
367  /* the next threads are binded with a round robin policy over this array */
368  wrap = 1;
369  nbr = i;
370 
371  coresbind[i] = coresbind[0];
372  }
373  }
374  else {
375  coresbind[i] = coresbind[i % nbr];
376  }
377  }
378  }
379  PLASMA_CLEANENV(envstr);
380  return PLASMA_SUCCESS;
381 }
382 
383 #ifdef __cplusplus
384 }
385 #endif
386 
387 #ifndef PLASMA_HAS_COMPLEX_H
388 
389 #ifdef __cplusplus
390 extern "C" {
391 #endif
392 float
393 cabsf(float _Complex z) {
394  float *zp, x, y;
395  zp = (float *)&z;
396 
397  /* first find out the large component */
398  if (zp[0] > zp[1]) {
399  x = zp[0];
400  y = zp[1];
401  } else {
402  x = zp[1];
403  y = zp[0];
404  }
405 
406  return fabsf(x) * sqrtf(1.0f + y / x);
407 }
408 
409 double
410 cabs(double _Complex z) {
411  double *zp, x, y;
412  zp = (double *)&z;
413 
414  /* first find out the large component */
415  if (zp[0] > zp[1]) {
416  x = zp[0];
417  y = zp[1];
418  } else {
419  x = zp[1];
420  y = zp[0];
421  }
422 
423  return fabs(x) * sqrt(1.0f + y / x);
424 }
425 
426 double
428  return ((double *)&z)[1];
429 }
430 double
432  return ((double *)&z)[0];
433 }
434 
437  double *zp, *vp;
439 
440  zp = (double *)&z;
441  vp = (double *)&v;
442  vp[0] = zp[0];
443  vp[1] = -zp[1];
444  return v;
445 }
446 
447 #ifdef __cplusplus
448 }
449 #endif
450 
451 #endif /* PLASMA_HAS_COMPLEX */