Alternative to shed_getaffinity, cpu_set_t etc?
Asked Answered
H

1

5

So I'm a noob when it comes to this sort of stuff.

I'm struggling to compile a climate model on macOS and I've boiled it down to what is going on here:

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <sys/resource.h>
#include <sys/syscall.h>

static pid_t gettid(void)
{
  return syscall(__NR_gettid);
}

/*                                                                                                                                                                                                                                 
 * Returns this thread's CPU affinity, if bound to a single core,                                                                                                                                                                  
 * or else -1.           




*/
int get_cpu_affinity(void)
{
  cpu_set_t coremask;           /* core affinity mask */

  CPU_ZERO(&coremask);
  if (sched_getaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
    fprintf(stderr,"Unable to get thread %d affinity. 

%s\n",gettid(),strerror(errno));
  }

  int cpu;
  int first_cpu = -1;   /* first CPU in range */
  int last_cpu = -1;    /* last CPU in range */
  for (cpu=0;cpu < CPU_SETSIZE;cpu++) {
    if (CPU_ISSET(cpu,&coremask)) {
      if (first_cpu == -1) {
         first_cpu = cpu;
      } else {
        last_cpu = cpu;
      }
    }
  }

  return (last_cpu == -1) ? first_cpu : -1;

}

int get_cpu_affinity_(void) { return get_cpu_affinity(); }      /* Fortran interface */


/*                                                                                                                                                                                                                                 
 * Set CPU affinity to one core.                                                                                                                                                                                                   
 */

void set_cpu_affinity( int cpu )
{
  cpu_set_t coremask;           /* core affinity mask */

  CPU_ZERO(&coremask);
  CPU_SET(cpu,&coremask);
  if (sched_setaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
    fprintf(stderr,"Unable to set thread %d affinity. %s\n",gettid(),strerror(errno));

  }
}

void set_cpu_affinity_(int *cpu) { set_cpu_affinity(*cpu); }    /* Fortran interface */

When compiling I get a couple of errors:

First - identifier "cpu_set_t" is undefined, Second - identifier "CPU_SETSIZE" is undefined

I've done my googling and it seems to me that sched_getaffinitiy(), cpu_set_t and perhaps some other things are not present in macOS.

With all kinds of C programming I'm really out of my depth. I was wondering if anyone here knows of an alternative way of doing this for macOS and how I could go about doing that.

I've attached the full error report below.

Kind Regards,

Neil :)

Complete error report:

(python2) salvare:MASTERS Neil$ python run.py
Working directory for exp 'playground' already exists
RRTM compilation disabled.  Namelist set to gray radiation.
Writing path_names to '/Users/Neil/MASTERS/ISCA_TEMP/playground/path_names'
Running compiler
/Users/Neil/MASTERS/ISCA_TEMP/playground/compile.sh: line 21: module: command not found
loadmodules
/Users/Neil/MASTERS/Isca/src/extra/loadmodule: line 3: module: command not found
/Users/Neil/MASTERS/Isca/src/extra/loadmodule: line 4: module: command not found
/Users/Neil/MASTERS/Isca/src/extra/loadmodule: line 5: module: command not found
/Users/Neil/MASTERS/Isca/src/extra/loadmodule: line 6: module: command not found
/Users/Neil/MASTERS/ISCA_TEMP/playground/compile.sh: line 23: module: command not found
/Users/Neil/MASTERS/ISCA_TEMP/playground/compile.sh: line 24: ulimit: stack size: cannot modify limit: Operation not permitted
./compile_mppn.sh: line 13: module: command not found
./compile_mppn.sh: line 14: module: command not found
./compile_mppn.sh: line 15: module: command not found
 - mppnccombine.c:162:24: warning: format string is not a string literal (potentially insecure) [-Wformat-security]
sprintf(outfilename,argv[outputarg]); outlen=strlen(outfilename);
^~~~~~~~~~~~~~~
/usr/include/secure/_stdio.h:47:56: note: expanded from macro 'sprintf'
__builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
^~~~~~~~~~~
mppnccombine.c:162:24: note: treat the string as an argument to avoid this
sprintf(outfilename,argv[outputarg]); outlen=strlen(outfilename);
 ^
"%s",
/usr/include/secure/_stdio.h:47:56: note: expanded from macro 'sprintf'
__builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
^
1 warning generated.
ln: /Users/Neil/MASTERS/ISCA_TEMP/playground/exec/mppnccombine.x: File exists
 Makefile is ready.
mpicc -Duse_libMPI -Duse_netCDF -Duse_LARGEFILE -DINTERNAL_FILE_NML -DOVERLOAD_C8 -DRRTM_NO_COMPILE -I/usr/local/include -D__IFC  -c    /Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c
 ......................................................................................................................../Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c(35): error: identifier "__NR_gettid" is undefined
eturn syscall(__NR_gettid);
 ^
/Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c(44): error: identifier "cpu_set_t" is undefined
cpu_set_t coremask;     /* core affinity mask */
^
 /Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c(47): error: identifier "cpu_set_t" is undefined
if (sched_getaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
^
/Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c(54): error: identifier "CPU_SETSIZE" is undefined
for (cpu=0;cpu < CPU_SETSIZE;cpu++) {
^
/Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c(75): error: identifier "cpu_set_t" is undefined
cpu_set_t coremask;     /* core affinity mask */
^
/Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c(79): error: identifier "cpu_set_t" is undefined
if (sched_setaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
 ^
compilation aborted for /Users/Neil/MASTERS/Isca/src/shared/mpp/affinity.c (code 2)
make: *** [affinity.o] Error 2
ERROR: mkmf failed for fms_moist
CRITICAL - Compilation failed.
Traceback (most recent call last):
  File "run.py", line 25, in <module>
    exp.compile()
  File "/Users/Neil/MASTERS/Isca/src/extra/python/gfdl/experiment.py", line 298, in compile
    raise e
sh.ErrorReturnCode_1: 

  RAN: /bin/bash /Users/Neil/MASTERS/ISCA_TEMP/playground/compile.sh

  STDOUT:


  STDERR:
Hygrophilous answered 21/7, 2017 at 0:9 Comment(0)
S
6

Your googling put you on the right track - sched_getaffinity() and the cpu_set_t structure that it uses are linux-specific, and are not available on all platforms. Mac OSX in particular seems to be missing them.

However, there are alternatives. I found a blog post from someone porting code to OSX who found an alternative using sysctlbyname(). The code on that site reimplements sched_getaffinity() on Mac OSX by requesting the machdep.cpu.core_count, and using that to build their own version of cpu_set_t.

Salesperson answered 21/7, 2017 at 0:48 Comment(2)
Thanks for finding this. Just a quick question.. again because my knowledge is quite basic. Once I've 'made' (copied) their version of cpu_set_t, how do I use it? I.e how do I make it that the above script can get to it? Thanks.Hygrophilous
@NeilLewis, just to make it clear, this is a "works for the author" implementation of the Linux affinity API. macOS affinity hints are just hints. There is no real equivalent to the hard thread/process binding/pinning that most other operating systems (even Windows) provide. This is a major bummer for some high-performance applications. I've seen cases where thread migration increases execution time by more than 50% on Linux.Nip

© 2022 - 2024 — McMap. All rights reserved.