ARGOBOTS
abtd_affinity.c
Go to the documentation of this file.
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  * See COPYRIGHT in top-level directory.
4  */
5 
6 #include "abti.h"
7 #include <unistd.h>
8 
9 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
10 #if defined(__FreeBSD__)
11 #include <sys/param.h>
12 #include <sys/cpuset.h>
13 #include <pthread_np.h>
14 
15 typedef cpuset_t cpu_set_t;
16 
17 static inline int ABTD_CPU_COUNT(cpu_set_t *p_cpuset)
18 {
19  int i, num_cpus = 0;
20  for (i = 0; i < CPU_SETSIZE; i++) {
21  if (CPU_ISSET(i, p_cpuset)) {
22  num_cpus++;
23  }
24  }
25  return num_cpus;
26 }
27 
28 #else
29 #define _GNU_SOURCE
30 #include <sched.h>
31 #define ABTD_CPU_COUNT CPU_COUNT
32 #endif
33 
34 enum {
35  ABTI_ES_AFFINITY_CHAMELEON,
36  ABTI_ES_AFFINITY_KNC,
37  ABTI_ES_AFFINITY_DEFAULT
38 };
39 static int g_affinity_type = ABTI_ES_AFFINITY_DEFAULT;
40 static cpu_set_t g_cpusets[CPU_SETSIZE];
41 static cpu_set_t g_initial_cpuset;
42 
43 static inline cpu_set_t ABTD_affinity_get_cpuset_for_rank(int rank)
44 {
45  int num_cores = gp_ABTI_global->num_cores;
46 
47  if (g_affinity_type == ABTI_ES_AFFINITY_CHAMELEON) {
48  int num_threads_per_socket = num_cores / 2;
49  int rem = rank % 2;
50  int socket_id = rank / num_threads_per_socket;
51  int target =
52  (rank - num_threads_per_socket * socket_id - rem + socket_id) +
53  num_threads_per_socket * rem;
54  return g_cpusets[target % num_cores];
55 
56  } else if (g_affinity_type == ABTI_ES_AFFINITY_KNC) {
57  /* NOTE: This is an experimental affinity mapping for Intel Xeon Phi
58  * (KNC). It seems that the OS kernel on KNC numbers contiguous CPU
59  * IDs at a single physical core and then moves to the next physical
60  * core. This numbering causes worse performance when we use a small
61  * number of physical cores. So, we set the ES affinity in a
62  * round-robin manner from the view of physical cores, not logical
63  * cores. */
64  const int NUM_HTHREAD = 4;
65  int NUM_PHYSICAL_CORES = num_cores / NUM_HTHREAD;
66  int target;
67  if (rank < NUM_PHYSICAL_CORES) {
68  target = NUM_HTHREAD * rank;
69  } else if (rank < NUM_PHYSICAL_CORES * 2) {
70  target = NUM_HTHREAD * (rank - NUM_PHYSICAL_CORES) + 1;
71  } else if (rank < NUM_PHYSICAL_CORES * 3) {
72  target = NUM_HTHREAD * (rank - NUM_PHYSICAL_CORES * 2) + 2;
73  } else {
74  target = NUM_HTHREAD * (rank - NUM_PHYSICAL_CORES * 3) + 3;
75  }
76  return g_cpusets[target % num_cores];
77 
78  } else {
79  return g_cpusets[rank % num_cores];
80  }
81 }
82 #endif
83 
84 void ABTD_affinity_init(void)
85 {
86 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
87  int i;
88  int num_cores = 0;
89 
90 #if defined(__FreeBSD__)
91  for (i = 0; i < CPU_SETSIZE; i++) {
92  CPU_ZERO(&g_cpusets[i]);
93  CPU_SET(i, &g_cpusets[i]);
94  }
95  num_cores = CPU_SETSIZE;
96 #else
97  i = sched_getaffinity(getpid(), sizeof(cpu_set_t), &g_initial_cpuset);
98  ABTI_ASSERT(i == 0);
99 
100  for (i = 0; i < CPU_SETSIZE; i++) {
101  CPU_ZERO(&g_cpusets[i]);
102  if (CPU_ISSET(i, &g_initial_cpuset)) {
103  CPU_SET(i, &g_cpusets[num_cores]);
104  num_cores++;
105  }
106  }
107 #endif
108  gp_ABTI_global->num_cores = num_cores;
109 
110  /* affinity type */
111  char *env = getenv("ABT_AFFINITY_TYPE");
112  if (env == NULL)
113  env = getenv("ABT_ENV_AFFINITY_TYPE");
114  if (env != NULL) {
115  if (strcmp(env, "chameleon") == 0) {
116  g_affinity_type = ABTI_ES_AFFINITY_CHAMELEON;
117  } else if (strcmp(env, "knc") == 0) {
118  g_affinity_type = ABTI_ES_AFFINITY_KNC;
119  }
120  }
121 #else
122  /* In this case, we don't support the ES affinity. */
123  gp_ABTI_global->set_affinity = ABT_FALSE;
124 #endif
125 }
126 
127 void ABTD_affinity_finalize(void)
128 {
129 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
130  pthread_t ctx = pthread_self();
131  pthread_setaffinity_np(ctx, sizeof(cpu_set_t), &g_initial_cpuset);
132 #endif
133 }
134 
135 int ABTD_affinity_set(ABTD_xstream_context *p_ctx, int rank)
136 {
137 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
138  int abt_errno;
139 
140  cpu_set_t cpuset = ABTD_affinity_get_cpuset_for_rank(rank);
141  if (!pthread_setaffinity_np(p_ctx->native_thread, sizeof(cpu_set_t),
142  &cpuset)) {
143  abt_errno = ABT_SUCCESS;
144  } else {
145  abt_errno = ABT_ERR_OTHER;
146  goto fn_fail;
147  }
148 
149 fn_exit:
150  return abt_errno;
151 
152 fn_fail:
153  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
154  goto fn_exit;
155 #else
156  return ABT_SUCCESS;
157 #endif
158 }
159 
160 int ABTD_affinity_set_cpuset(ABTD_xstream_context *p_ctx, int cpuset_size,
161  int *p_cpuset)
162 {
163 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
164  int abt_errno = ABT_SUCCESS;
165  int i;
166  cpu_set_t cpuset;
167 
168  CPU_ZERO(&cpuset);
169  for (i = 0; i < cpuset_size; i++) {
170  ABTI_ASSERT(p_cpuset[i] < CPU_SETSIZE);
171  CPU_SET(p_cpuset[i], &cpuset);
172  }
173 
174  i = pthread_setaffinity_np(p_ctx->native_thread, sizeof(cpu_set_t),
175  &cpuset);
176  ABTI_CHECK_TRUE(!i, ABT_ERR_OTHER);
177 
178 fn_exit:
179  return abt_errno;
180 
181 fn_fail:
182  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
183  goto fn_exit;
184 #else
185  return ABT_ERR_FEATURE_NA;
186 #endif
187 }
188 
189 int ABTD_affinity_get_cpuset(ABTD_xstream_context *p_ctx, int cpuset_size,
190  int *p_cpuset, int *p_num_cpus)
191 {
192 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
193  int abt_errno = ABT_SUCCESS;
194  int i;
195  cpu_set_t cpuset;
196  int num_cpus = 0;
197 
198  i = pthread_getaffinity_np(p_ctx->native_thread, sizeof(cpu_set_t),
199  &cpuset);
200  ABTI_CHECK_TRUE(!i, ABT_ERR_OTHER);
201 
202  if (p_cpuset != NULL) {
203  for (i = 0; i < CPU_SETSIZE; i++) {
204  if (CPU_ISSET(i, &cpuset)) {
205  if (num_cpus < cpuset_size) {
206  p_cpuset[num_cpus] = i;
207  } else {
208  break;
209  }
210  num_cpus++;
211  }
212  }
213  }
214 
215  if (p_num_cpus != NULL) {
216  *p_num_cpus = ABTD_CPU_COUNT(&cpuset);
217  }
218 
219 fn_exit:
220  return abt_errno;
221 
222 fn_fail:
223  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
224  goto fn_exit;
225 #else
226  return ABT_ERR_FEATURE_NA;
227 #endif
228 }
#define ABT_ERR_OTHER
Definition: abt.h:67
#define ABT_FALSE
Definition: abt.h:224
#define HANDLE_ERROR_FUNC_WITH_CODE(n)
Definition: abti_error.h:241
ABTI_global * gp_ABTI_global
Definition: global.c:14
#define ABT_SUCCESS
Definition: abt.h:64
#define ABT_ERR_FEATURE_NA
Definition: abt.h:115