FMS  2025.04
Flexible Modeling System
affinity.c
1 /***********************************************************************
2  * Apache License 2.0
3  *
4  * This file is part of the GFDL Flexible Modeling System (FMS).
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * FMS is distributed in the hope that it will be useful, but WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15  * PARTICULAR PURPOSE. See the License for the specific language
16  * governing permissions and limitations under the License.
17  ***********************************************************************/
18 
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdbool.h>
27 #include <unistd.h>
28 #include <sched.h>
29 #include <errno.h>
30 #include <sys/resource.h>
31 #include <sys/syscall.h>
32 #ifdef __APPLE__
33 #include <pthread.h>
34 #endif
35 /** \endcond
36  */
37 // skips doc parsing for includes and license
38 
39 /**
40  * \addtogroup affinity
41  * \@{
42  */
43 
44 /**
45  * gettid function for systems that do not have this function (e.g. on Mac OS.)
46  */
47 #ifndef HAVE_GETTID
48 static pid_t gettid(void)
49 {
50 #if defined(__APPLE__)
51  uint64_t tid64;
52  pthread_threadid_np(NULL, &tid64);
53  pid_t tid = (pid_t)tid64;
54 #else
55  pid_t tid = syscall(__NR_gettid);
56 #endif
57  return tid;
58 }
59 #endif
60 
61 /**
62  * Returns this thread's CPU affinity, if bound to a single core,
63  * or else -1.
64  */
65 int get_cpu_affinity(void)
66 {
67 #ifdef HAVE_SCHED_GETAFFINITY
68  cpu_set_t coremask; /* core affinity mask */
69 
70  CPU_ZERO(&coremask);
71  if (sched_getaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
72  fprintf(stderr,"Unable to get thread %d affinity. %s\n",gettid(),strerror(errno));
73  }
74 
75  int cpu;
76  for (cpu=0;cpu < CPU_SETSIZE;cpu++) {
77  if (CPU_ISSET(cpu,&coremask)) {
78  return cpu;
79  }
80  }
81 #endif
82  return -1;
83 }
84 
85 /**
86  * Returns this groups CPUSET
87  * and also the CPUSET size or -1 (in case of a storage error)
88  */
89 int get_cpuset(int fsz, int *output, int pe, _Bool debug)
90 {
91 #ifdef HAVE_SCHED_GETAFFINITY
92  cpu_set_t coremask; /* core affinity mask */
93 
94  CPU_ZERO(&coremask);
95  if (sched_getaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
96  fprintf(stderr,"Unable to get thread %d affinity. %s\n",gettid(),strerror(errno));
97  }
98 
99  int cpu;
100  int count;
101 
102  if (debug) {
103  for (cpu=0;cpu < CPU_SETSIZE;cpu++) {
104  if (CPU_ISSET(cpu,&coremask)) {
105  printf("=> get_cpuset - pe %d: %d\n",pe, cpu);
106  }
107  }
108  }
109 
110  count = 0;
111  for (cpu=0;cpu < CPU_SETSIZE;cpu++) {
112  if (CPU_ISSET(cpu,&coremask)) {
113  if (count > fsz) {
114  return -1;
115  }
116  output[count] = cpu;
117  count ++;
118  }
119  }
120  return count;
121 #else
122  return fsz;
123 #endif
124 }
125 
126 /**
127  * Set CPU affinity to one core.
128  */
129 int set_cpu_affinity(int cpu)
130 {
131 #ifdef HAVE_SCHED_GETAFFINITY
132  cpu_set_t coremask; /* core affinity mask */
133 
134  CPU_ZERO(&coremask);
135  CPU_SET(cpu,&coremask);
136  if (sched_setaffinity(gettid(),sizeof(cpu_set_t),&coremask) != 0) {
137  return -1;
138  }
139 #endif
140  return 0;
141 }
142 ///@}
integer function stderr()
This function returns the current standard fortran unit numbers for error messages.
Definition: mpp_util.inc:50