QUARK  0.9.0
QUARK-QUeuingAndRuntimeforKernels
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
quarkos.c
Go to the documentation of this file.
1 
18 #if defined(linux) || defined(__linux) || defined(__linux__)
19 #define QUARK_OS_LINUX 1
20 #define _GNU_SOURCE
21 #include <unistd.h>
22 #include <sched.h>
23 #elif defined( _WIN32 ) || defined( _WIN64 )
24 #define QUARK_OS_WINDOWS 1
25 #include <Windows.h>
26 #elif (defined __APPLE__) || (defined macintosh) || (defined __MACOSX__)
27 #define QUARK_OS_MACOS 1
28 #include <sys/param.h>
29 #include <sys/sysctl.h>
30 #include <mach/mach_init.h>
31 #include <mach/thread_policy.h>
32 kern_return_t thread_policy_set(thread_act_t thread, thread_policy_flavor_t flavor,
33  thread_policy_t policy_info, mach_msg_type_number_t count);
34 #elif (defined _AIX)
35 #define QUARK_OS_AIX 1
36 #else
37 #error "Cannot find the runing system or system not supported. Please define try to QUARK_OS_[LINUX|MACOS|AIX|WINDOWS]"
38 #endif
39 
40 #if defined(QUARK_HWLOC) && (defined QUARK_AFFINITY_DISABLE)
41 #undef QUARK_HWLOC
42 #endif
43 
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 //#include "common.h"
48 #if defined( _WIN32 ) || defined( _WIN64 )
49 #include "quarkwinthread.h"
50 #else
51 #include <pthread.h>
52 #endif
53 
54 #include "quark.h"
55 void quark_warning(const char *func_name, char* msg_text);
56 #define QUARK_SUCCESS 0
57 #define QUARK_ERR -1
58 #define QUARK_ERR_UNEXPECTED -1
59 
60 // maximum cores per context
61 #define CONTEXT_THREADS_MAX 256
62 
63 
64 #ifdef __cplusplus
65 extern "C" {
66 #endif
67 
69 static volatile int sys_corenbr = 1;
70 static volatile int topo_initialized = 0;
71 
72  /*
73  * Topology functions
74  */
75 #ifdef QUARK_HWLOC
76 #include "quarkos-hwloc.c"
77 #else
78 
80  pthread_mutex_lock(&mutextopo);
81  if ( !topo_initialized ) {
82 #if (defined QUARK_OS_LINUX) || (defined QUARK_OS_AIX)
83 
84  sys_corenbr = sysconf(_SC_NPROCESSORS_ONLN);
85 
86 #elif (defined QUARK_OS_MACOS)
87 
88  int mib[4];
89  int cpu;
90  size_t len = sizeof(cpu);
91 
92  /* set the mib for hw.ncpu */
93  mib[0] = CTL_HW;
94  mib[1] = HW_AVAILCPU;
95 
96  /* get the number of CPUs from the system */
97  sysctl(mib, 2, &cpu, &len, NULL, 0);
98  if( cpu < 1 ) {
99  mib[1] = HW_NCPU;
100  sysctl( mib, 2, &cpu, &len, NULL, 0 );
101  }
102  if( cpu < 1 ) {
103  cpu = 1;
104  }
105  sys_corenbr = cpu;
106 #elif (defined QUARK_OS_WINDOWS)
107  SYSTEM_INFO sysinfo;
108  GetSystemInfo(&sysinfo);
109  sys_corenbr = sysinfo.dwNumberOfProcessors;
110 #endif
111  }
112  pthread_mutex_unlock(&mutextopo);
113 }
114 
116 {
118 }
119 
129 int quark_setaffinity(int rank) {
130 #ifndef QUARK_AFFINITY_DISABLE
131 #if (defined QUARK_OS_LINUX)
132  {
133  cpu_set_t set;
134  CPU_ZERO( &set );
135  CPU_SET( rank, &set );
136 
137 #if (defined HAVE_OLD_SCHED_SETAFFINITY)
138  if( sched_setaffinity( 0, &set ) < 0 )
139 #else /* HAVE_OLD_SCHED_SETAFFINITY */
140  if( sched_setaffinity( 0, sizeof(set), &set) < 0 )
141 #endif /* HAVE_OLD_SCHED_SETAFFINITY */
142  {
143  return QUARK_ERR_UNEXPECTED;
144  }
145 
146  return QUARK_SUCCESS;
147  }
148 #elif (defined QUARK_OS_MACOS)
149  {
150  thread_affinity_policy_data_t ap;
151  int ret;
152 
153  ap.affinity_tag = 1; /* non-null affinity tag */
154  ret = thread_policy_set( mach_thread_self(),
155  THREAD_AFFINITY_POLICY,
156  (integer_t*) &ap,
157  THREAD_AFFINITY_POLICY_COUNT
158  );
159  if(ret != 0)
160  return QUARK_ERR_UNEXPECTED;
161 
162  return QUARK_SUCCESS;
163  }
164 #elif (defined QUARK_OS_WINDOWS)
165  {
166  DWORD mask = 1 << rank;
167 
168  if( SetThreadAffinityMask(GetCurrentThread(), mask) == 0)
169  return QUARK_ERR_UNEXPECTED;
170 
171  return QUARK_SUCCESS;
172  }
173 #elif (defined QUARK_OS_AIX)
174  {
175  tid_t self_ktid = thread_self ();
176  bindprocessor(BINDTHREAD, self_ktid, rank);
177  return QUARK_SUCCESS;
178  }
179 #else
181 #endif
182 #endif /* QUARK_AFFINITY_DISABLE */
184 }
185 
186 
196 int quark_unsetaffinity(int rank) {
197 #ifndef QUARK_AFFINITY_DISABLE
198 #if (defined QUARK_OS_LINUX)
199  {
200  int i;
201  cpu_set_t set;
202  CPU_ZERO( &set );
203 
204  for(i=0; i<sys_corenbr; i++)
205  CPU_SET( i, &set );
206 
207 #if (defined HAVE_OLD_SCHED_SETAFFINITY)
208  if( sched_setaffinity( 0, &set ) < 0 )
209 #else /* HAVE_OLD_SCHED_SETAFFINITY */
210  if( sched_setaffinity( 0, sizeof(set), &set) < 0 )
211 #endif /* HAVE_OLD_SCHED_SETAFFINITY */
212  {
213  quark_warning("quark_unsetaffinity", "Could not unbind thread");
214  return QUARK_ERR_UNEXPECTED;
215  }
216 
217  return QUARK_SUCCESS;
218  }
219 #elif (defined QUARK_OS_MACOS)
220  {
221  /* TODO: check how to unbind the main thread if necessary for OpenMP */
222  /* thread_affinity_policy_data_t ap; */
223  /* int ret; */
224 
225  /* ap.affinity_tag = 1; /\* non-null affinity tag *\/ */
226  /* ret = thread_policy_set( mach_thread_self(), */
227  /* THREAD_AFFINITY_POLICY, */
228  /* (integer_t*) &ap, */
229  /* THREAD_AFFINITY_POLICY_COUNT */
230  /* ); */
231  /* if(ret != 0) { */
232  /* quark_warning("quark_unsetaffinity", "Could not unbind thread"); */
233  /* return QUARK_ERR_UNEXPECTED; */
234  /* } */
235 
236  return QUARK_SUCCESS;
237  }
238 #elif (defined QUARK_OS_WINDOWS)
239  {
240  int i;
241  DWORD mask = 0;
242 
243  for(i=0; i<sys_corenbr; i++)
244  mask |= 1 << i;
245 
246  if( SetThreadAffinityMask(GetCurrentThread(), mask) == 0) {
247  quark_warning("quark_unsetaffinity", "Could not unbind thread");
248  return QUARK_ERR_UNEXPECTED;
249  }
250  return QUARK_SUCCESS;
251  }
252 #elif (defined QUARK_OS_AIX)
253  {
254  /* TODO: check how to unbind the main thread if necessary for OpenMP */
255  /* tid_t self_ktid = thread_self (); */
256  /* bindprocessor(BINDTHREAD, self_ktid, rank); */
257  return QUARK_SUCCESS;
258  }
259 #else
261 #endif
262 #endif /* QUARK_AFFINITY_DISABLE */
263 }
264 
265 #endif /* QUARK_HWLOC */
266 
271 int quark_yield() {
272 #if (defined QUARK_OS_LINUX) || (defined QUARK_OS_MACOS) || (defined QUARK_OS_AIX)
273  return sched_yield();
274 #elif QUARK_OS_WINDOWS
275  return SleepEx(0,0);
276 #else
278 #endif
279 }
280 
281 #ifdef QUARK_OS_WINDOWS
282 #define QUARK_GETENV(var, str) { \
283  int len = 512; \
284  int ret; \
285  str = (char*)malloc(len * sizeof(char)); \
286  ret = GetEnvironmentVariable(var, str, len); \
287  if (ret == 0) { \
288  free(str); \
289  str = NULL; \
290  } \
291  }
292 
293 #define QUARK_CLEANENV(str) if (str != NULL) free(str);
294 
295 #else /* Other OS systems */
296 
297 #define QUARK_GETENV(var, str) envstr = getenv(var);
298 #define QUARK_CLEANENV(str)
299 
300 #endif
301 
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  QUARK_GETENV("QUARK_NUM_THREADS", envstr);
315  if ( envstr == NULL ) {
316  thrdnbr = sys_corenbr;
317  } else {
318  /* Convert to long, checking for errors */
319  thrdnbr = strtol(envstr, &endptr, 10);
320  if ((errno == ERANGE) || ((thrdnbr==0) && (endptr==envstr))) {
321  QUARK_CLEANENV(envstr);
322  return -1;
323  }
324  }
325  QUARK_CLEANENV(envstr);
326  return (int)thrdnbr;
327 }
328 
329 int *quark_get_affthreads(/* int *coresbind */) {
330  char *envstr = NULL;
331  int i;
332 
333  int *coresbind = (int *)malloc(CONTEXT_THREADS_MAX*sizeof(int));
334  /* Env variable does not exist, we search the system number of core */
335  QUARK_GETENV("QUARK_AFF_THREADS", envstr);
336  if ( envstr == NULL) {
337  for (i = 0; i < CONTEXT_THREADS_MAX; i++)
338  coresbind[i] = i % sys_corenbr;
339  }
340  else {
341  char *endptr;
342  int wrap = 0;
343  int nbr = 0;
344  long int val;
345 
346  /* We use the content of the QUARK_AFF_THREADS env. variable */
347  for (i = 0; i < CONTEXT_THREADS_MAX; i++) {
348  if (!wrap) {
349  val = strtol(envstr, &endptr, 10);
350  if (endptr != envstr) {
351  coresbind[i] = (int)val;
352  envstr = endptr;
353  }
354  else {
355  /* there must be at least one entry */
356  if (i < 1) {
357  //quark_error("quark_get_affthreads", "QUARK_AFF_THREADS should have at least one entry => everything will be bind on core 0");
358  fprintf(stderr, "quark_get_affthreads: QUARK_AFF_THREADS should have at least one entry => everything will be bind on core 0");
359  coresbind[i] = 0;
360  i++;
361  }
362 
363  /* there is no more values in the string */
364  /* the next threads are binded with a round robin policy over this array */
365  wrap = 1;
366  nbr = i;
367 
368  coresbind[i] = coresbind[0];
369  }
370  }
371  else {
372  coresbind[i] = coresbind[i % nbr];
373  }
374  }
375  }
376  QUARK_CLEANENV(envstr);
377  /* return QUARK_SUCCESS; */
378  return coresbind;
379 }
380 
381 
384 int quark_getenv_int(char* name, int defval)
385 {
386  char *envstr = NULL;
387  char *endptr;
388  long int longval = -1;
389  extern int errno;
390 
391  QUARK_GETENV(name, envstr);
392  if ( envstr == NULL ) {
393  longval = defval;
394  } else {
395  /* Convert to long, checking for errors */
396  longval = strtol(envstr, &endptr, 10);
397  if ((errno == ERANGE) || ((longval==0) && (endptr==envstr))) {
398  longval = defval;
399  }
400  }
401  QUARK_CLEANENV(envstr);
402  return (int)longval;
403 }
404 
405 
406 #ifdef __cplusplus
407 }
408 #endif
409