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