vlib: improve automatic core pinning
[vpp.git] / src / vppinfra / unix-misc.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2005 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <vppinfra/error.h>
39 #include <vppinfra/os.h>
40 #include <vppinfra/bitmap.h>
41 #include <vppinfra/unix.h>
42 #include <vppinfra/format.h>
43 #ifdef __linux__
44 #include <vppinfra/linux/sysfs.h>
45 #endif
46
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <sys/syscall.h>
50 #include <sys/uio.h>            /* writev */
51 #include <fcntl.h>
52 #include <stdio.h>              /* for sprintf */
53 #include <limits.h>
54
55 __clib_export __thread uword __os_thread_index = 0;
56 __clib_export __thread uword __os_numa_index = 0;
57
58 clib_error_t *
59 clib_file_n_bytes (char *file, uword * result)
60 {
61   struct stat s;
62
63   if (stat (file, &s) < 0)
64     return clib_error_return_unix (0, "stat `%s'", file);
65
66   if (S_ISREG (s.st_mode))
67     *result = s.st_size;
68   else
69     *result = 0;
70
71   return /* no error */ 0;
72 }
73
74 clib_error_t *
75 clib_file_read_contents (char *file, u8 * result, uword n_bytes)
76 {
77   int fd = -1;
78   uword n_done, n_left;
79   clib_error_t *error = 0;
80   u8 *v = result;
81
82   if ((fd = open (file, 0)) < 0)
83     return clib_error_return_unix (0, "open `%s'", file);
84
85   n_left = n_bytes;
86   n_done = 0;
87   while (n_left > 0)
88     {
89       int n_read;
90       if ((n_read = read (fd, v + n_done, n_left)) < 0)
91         {
92           error = clib_error_return_unix (0, "open `%s'", file);
93           goto done;
94         }
95
96       /* End of file. */
97       if (n_read == 0)
98         break;
99
100       n_left -= n_read;
101       n_done += n_read;
102     }
103
104   if (n_left > 0)
105     {
106       error =
107         clib_error_return (0,
108                            " `%s' expected to read %wd bytes; read only %wd",
109                            file, n_bytes, n_bytes - n_left);
110       goto done;
111     }
112
113 done:
114   close (fd);
115   return error;
116 }
117
118 __clib_export clib_error_t *
119 clib_file_contents (char *file, u8 ** result)
120 {
121   uword n_bytes;
122   clib_error_t *error = 0;
123   u8 *v;
124
125   if ((error = clib_file_n_bytes (file, &n_bytes)))
126     return error;
127
128   v = 0;
129   vec_resize (v, n_bytes);
130
131   error = clib_file_read_contents (file, v, n_bytes);
132
133   if (error)
134     vec_free (v);
135   else
136     *result = v;
137
138   return error;
139 }
140
141 __clib_export u8 *
142 clib_file_get_resolved_basename (char *fmt, ...)
143 {
144   va_list va;
145   char *p, buffer[PATH_MAX];
146   u8 *link, *s = 0;
147   int r;
148
149   va_start (va, fmt);
150   link = va_format (0, fmt, &va);
151   va_end (va);
152   vec_add1 (link, 0);
153
154   r = readlink ((char *) link, buffer, sizeof (buffer) - 1);
155   vec_free (link);
156
157   if (r < 1)
158     return 0;
159
160   buffer[r] = 0;
161   p = buffer + r - 1;
162   while (p > buffer && p[-1] != '/')
163     p--;
164
165   while (p[0])
166     vec_add1 (s, p++[0]);
167
168   vec_add1 (s, 0);
169   return s;
170 }
171
172 clib_error_t *
173 unix_proc_file_contents (char *file, u8 ** result)
174 {
175   u8 *rv = 0;
176   uword pos;
177   int bytes, fd;
178
179   /* Unfortunately, stat(/proc/XXX) returns zero... */
180   fd = open (file, O_RDONLY);
181
182   if (fd < 0)
183     return clib_error_return_unix (0, "open `%s'", file);
184
185   vec_validate (rv, 4095);
186   pos = 0;
187   while (1)
188     {
189       bytes = read (fd, rv + pos, 4096);
190       if (bytes < 0)
191         {
192           close (fd);
193           vec_free (rv);
194           return clib_error_return_unix (0, "read '%s'", file);
195         }
196
197       if (bytes == 0)
198         {
199           vec_set_len (rv, pos);
200           break;
201         }
202       pos += bytes;
203       vec_validate (rv, pos + 4095);
204     }
205   *result = rv;
206   close (fd);
207   return 0;
208 }
209
210 void os_panic (void) __attribute__ ((weak));
211
212 __clib_export void
213 os_panic (void)
214 {
215   abort ();
216 }
217
218 void os_exit (int) __attribute__ ((weak));
219
220 void
221 os_exit (int code)
222 {
223   exit (code);
224 }
225
226 void os_puts (u8 * string, uword string_length, uword is_error)
227   __attribute__ ((weak));
228
229 void
230 os_puts (u8 * string, uword string_length, uword is_error)
231 {
232   int cpu = os_get_thread_index ();
233   int nthreads = os_get_nthreads ();
234   char buf[64];
235   int fd = is_error ? 2 : 1;
236   struct iovec iovs[2];
237   int n_iovs = 0;
238
239   if (nthreads > 1)
240     {
241       snprintf (buf, sizeof (buf), "%d: ", cpu);
242
243       iovs[n_iovs].iov_base = buf;
244       iovs[n_iovs].iov_len = strlen (buf);
245       n_iovs++;
246     }
247
248   iovs[n_iovs].iov_base = string;
249   iovs[n_iovs].iov_len = string_length;
250   n_iovs++;
251
252   if (writev (fd, iovs, n_iovs) < 0)
253     ;
254 }
255
256 __clib_export __clib_weak void
257 os_out_of_memory (void)
258 {
259   os_panic ();
260 }
261
262 __clib_export __clib_weak uword
263 os_get_nthreads (void)
264 {
265   return 1;
266 }
267
268 __clib_export clib_bitmap_t *
269 os_get_online_cpu_core_bitmap ()
270 {
271 #if __linux__
272   return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
273 #else
274   return 0;
275 #endif
276 }
277
278 __clib_export clib_bitmap_t *
279 os_get_cpu_affinity_bitmap (int pid)
280 {
281 #if __linux
282   int index, ret;
283   cpu_set_t cpuset;
284   uword *affinity_cpus;
285
286   clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t));
287   clib_bitmap_zero (affinity_cpus);
288
289   __CPU_ZERO_S (sizeof (cpu_set_t), &cpuset);
290
291   ret = syscall (SYS_sched_getaffinity, 0, sizeof (cpu_set_t), &cpuset);
292
293   if (ret < 0)
294     {
295       clib_bitmap_free (affinity_cpus);
296       return 0;
297     }
298
299   for (index = 0; index < sizeof (cpu_set_t); index++)
300     if (__CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset))
301       clib_bitmap_set (affinity_cpus, index, 1);
302   return affinity_cpus;
303 #else
304   return 0;
305 #endif
306 }
307
308 __clib_export clib_bitmap_t *
309 os_get_online_cpu_node_bitmap ()
310 {
311 #if __linux__
312   return clib_sysfs_read_bitmap ("/sys/devices/system/node/online");
313 #else
314   return 0;
315 #endif
316 }
317 __clib_export clib_bitmap_t *
318 os_get_cpu_on_node_bitmap (int node)
319 {
320 #if __linux__
321   return clib_sysfs_read_bitmap ("/sys/devices/system/node/node%u/cpulist",
322                                  node);
323 #else
324   return 0;
325 #endif
326 }
327
328 __clib_export clib_bitmap_t *
329 os_get_cpu_with_memory_bitmap ()
330 {
331 #if __linux__
332   return clib_sysfs_read_bitmap ("/sys/devices/system/node/has_memory");
333 #else
334   return 0;
335 #endif
336 }
337
338 __clib_export int
339 os_get_cpu_phys_core_id (int cpu_id)
340 {
341 #if __linux
342   int core_id = -1;
343   clib_error_t *err;
344   u8 *p;
345
346   p =
347     format (0, "/sys/devices/system/cpu/cpu%u/topology/core_id%c", cpu_id, 0);
348   err = clib_sysfs_read ((char *) p, "%d", &core_id);
349   vec_free (p);
350   if (err)
351     {
352       clib_error_free (err);
353       return -1;
354     }
355   return core_id;
356 #else
357   return -1;
358 #endif
359 }
360
361 /*
362  * fd.io coding-style-patch-verification: ON
363  *
364  * Local Variables:
365  * eval: (c-set-style "gnu")
366  * End:
367  */