1 /**
2 * @file fg_affinity.c
3 * @brief CPU affinity routines used by Flowgrind
4 */
5
6 /*
7 * Copyright (C) 2014 Alexander Zimmermann <alexander.zimmermann@netapp.com>
8 *
9 * This file is part of Flowgrind.
10 *
11 * Flowgrind is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * Flowgrind is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Flowgrind. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29
30 #ifdef HAVE_PTHREAD_NP_H
31 #include <pthread_np.h>
32 #endif /* HAVE_PTHREAD_NP */
33
34 #ifdef HAVE_SYS_CPUSET_H
35 #include <sys/param.h>
36 #include <sys/cpuset.h>
37 #endif /* HAVE_SYS_CPUSET */
38
39 /* OS X hasn't defined pthread_[set|get]affinity_np */
40 #if !defined(HAVE_PTHREAD_AFFINITY_NP) && defined HAVE_THREAD_POLICY
41 #include <mach/mach.h>
42 #include <mach/thread_policy.h>
43 #endif /* !defined(HAVE_PTHREAD_AFFINITY_NP) && defined HAVE_THREAD_POLICY */
44
45 #include <stdbool.h>
46 #include <errno.h>
47 #include <unistd.h>
48
49 #include "fg_affinity.h"
50
51 #if (!(HAVE_CPU_SET_T) && HAVE_CPUSET_T)
52 /** FreeBSD defines cpuset_t instead of cpu_set_t. Note kFreeBSD defines both. */
53 typedef cpuset_t cpu_set_t;
54 #endif /* HAVE_CPUSET_T */
55
get_ncores(enum ncore_query query)56 int get_ncores(enum ncore_query query)
57 {
58 switch (query) {
59 case NCORE_CONFIG:
60 /* processors configured */
61 return (int)sysconf(_SC_NPROCESSORS_CONF);
62 break;
63 case NCORE_CURRENT:
64 /* processors available */
65 return (int)sysconf(_SC_NPROCESSORS_ONLN);
66 break;
67 default:
68 errno = EINVAL;
69 return -1;
70 }
71 }
72
73 /* Linux and FreeBSD have pthread_[set|get]affinity_np */
74 #if defined HAVE_PTHREAD_AFFINITY_NP
pthread_setaffinity(pthread_t thread,unsigned core)75 int pthread_setaffinity(pthread_t thread, unsigned core)
76 {
77 cpu_set_t cpuset;
78 CPU_ZERO(&cpuset);
79 CPU_SET(core, &cpuset);
80
81 int rc = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
82 return (rc == 0 ? 0 : -1);
83 }
84
pthread_getaffinity(pthread_t thread,unsigned * core)85 int pthread_getaffinity(pthread_t thread, unsigned *core)
86 {
87 cpu_set_t cpuset;
88 int rc = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
89 if (rc)
90 return -1;
91
92 /* If the cpuset contains only one CPU, then that's the answer. For
93 * all other cpuset contents, we treat the binding as unknown */
94 core = NULL;
95 bool core_found = false;
96 for (unsigned i = 0; i < CPU_SETSIZE; i++) {
97 if (CPU_ISSET(i, &cpuset)) {
98 if (!core_found) {
99 core_found = true;
100 *core = i;
101 } else {
102 core_found = false;
103 core = NULL;
104 break;
105 }
106 }
107 }
108
109 return (core_found ? 0 : -1);
110 }
111 /* OS X hasn't defined pthread_[set|get]affinity_np */
112 #elif defined HAVE_THREAD_POLICY
pthread_setaffinity(pthread_t thread,unsigned core)113 int pthread_setaffinity(pthread_t thread, unsigned core)
114 {
115 /* Convert pthread ID */
116 mach_port_t mach_thread = pthread_mach_thread_np(thread);
117 /* core + 1 to avoid using THREAD_AFFINITY_TAG_NULL */
118 thread_affinity_policy_data_t policy = { core + 1 };
119
120 kern_return_t rc = thread_policy_set(mach_thread,
121 THREAD_AFFINITY_POLICY,
122 (thread_policy_t) &policy,
123 THREAD_AFFINITY_POLICY_COUNT);
124
125 return (rc == KERN_SUCCESS ? 0 : -1);
126 }
127
pthread_getaffinity(pthread_t thread,unsigned * core)128 int pthread_getaffinity(pthread_t thread, unsigned *core)
129 {
130 /* Convert pthread ID */
131 mach_port_t mach_thread = pthread_mach_thread_np(thread);
132 thread_affinity_policy_data_t policy;
133 mach_msg_type_number_t count = THREAD_AFFINITY_POLICY_COUNT;
134 boolean_t get_default = FALSE;
135
136 kern_return_t rc = thread_policy_get(mach_thread,
137 THREAD_AFFINITY_POLICY,
138 (thread_policy_t) &policy, &count,
139 &get_default);
140 *core = (unsigned)policy.affinity_tag;
141
142 return (rc == KERN_SUCCESS ? 0 : -1);
143 }
144 #endif /* HAVE_PTHREAD_AFFINITY_NP */
145