1 /*
2 * Copyright 2013-2015, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6 #define _GNU_SOURCE /* For CPU_ZERO etc. */
7
8 #include <elf.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <link.h>
12 #include <sched.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <sys/sysinfo.h>
17 #include <sys/types.h>
18 #include <sys/utsname.h>
19 #include <unistd.h>
20
21 #include "utils.h"
22
23 static char auxv[4096];
24
read_auxv(char * buf,ssize_t buf_size)25 int read_auxv(char *buf, ssize_t buf_size)
26 {
27 ssize_t num;
28 int rc, fd;
29
30 fd = open("/proc/self/auxv", O_RDONLY);
31 if (fd == -1) {
32 perror("open");
33 return -errno;
34 }
35
36 num = read(fd, buf, buf_size);
37 if (num < 0) {
38 perror("read");
39 rc = -EIO;
40 goto out;
41 }
42
43 if (num > buf_size) {
44 printf("overflowed auxv buffer\n");
45 rc = -EOVERFLOW;
46 goto out;
47 }
48
49 rc = 0;
50 out:
51 close(fd);
52 return rc;
53 }
54
find_auxv_entry(int type,char * auxv)55 void *find_auxv_entry(int type, char *auxv)
56 {
57 ElfW(auxv_t) *p;
58
59 p = (ElfW(auxv_t) *)auxv;
60
61 while (p->a_type != AT_NULL) {
62 if (p->a_type == type)
63 return p;
64
65 p++;
66 }
67
68 return NULL;
69 }
70
get_auxv_entry(int type)71 void *get_auxv_entry(int type)
72 {
73 ElfW(auxv_t) *p;
74
75 if (read_auxv(auxv, sizeof(auxv)))
76 return NULL;
77
78 p = find_auxv_entry(type, auxv);
79 if (p)
80 return (void *)p->a_un.a_val;
81
82 return NULL;
83 }
84
pick_online_cpu(void)85 int pick_online_cpu(void)
86 {
87 int ncpus, cpu = -1;
88 cpu_set_t *mask;
89 size_t size;
90
91 ncpus = get_nprocs_conf();
92 size = CPU_ALLOC_SIZE(ncpus);
93 mask = CPU_ALLOC(ncpus);
94 if (!mask) {
95 perror("malloc");
96 return -1;
97 }
98
99 CPU_ZERO_S(size, mask);
100
101 if (sched_getaffinity(0, size, mask)) {
102 perror("sched_getaffinity");
103 goto done;
104 }
105
106 /* We prefer a primary thread, but skip 0 */
107 for (cpu = 8; cpu < ncpus; cpu += 8)
108 if (CPU_ISSET_S(cpu, size, mask))
109 goto done;
110
111 /* Search for anything, but in reverse */
112 for (cpu = ncpus - 1; cpu >= 0; cpu--)
113 if (CPU_ISSET_S(cpu, size, mask))
114 goto done;
115
116 printf("No cpus in affinity mask?!\n");
117
118 done:
119 CPU_FREE(mask);
120 return cpu;
121 }
122
is_ppc64le(void)123 bool is_ppc64le(void)
124 {
125 struct utsname uts;
126 int rc;
127
128 errno = 0;
129 rc = uname(&uts);
130 if (rc) {
131 perror("uname");
132 return false;
133 }
134
135 return strcmp(uts.machine, "ppc64le") == 0;
136 }
137