0001
0002
0003
0004
0005
0006 #define _GNU_SOURCE
0007
0008 #include <elf.h>
0009 #include <errno.h>
0010 #include <fcntl.h>
0011 #include <link.h>
0012 #include <sched.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <sys/ioctl.h>
0017 #include <sys/stat.h>
0018 #include <sys/sysinfo.h>
0019 #include <sys/types.h>
0020 #include <sys/utsname.h>
0021 #include <unistd.h>
0022 #include <asm/unistd.h>
0023 #include <linux/limits.h>
0024
0025 #include "utils.h"
0026
0027 static char auxv[4096];
0028
0029 int read_auxv(char *buf, ssize_t buf_size)
0030 {
0031 ssize_t num;
0032 int rc, fd;
0033
0034 fd = open("/proc/self/auxv", O_RDONLY);
0035 if (fd == -1) {
0036 perror("open");
0037 return -errno;
0038 }
0039
0040 num = read(fd, buf, buf_size);
0041 if (num < 0) {
0042 perror("read");
0043 rc = -EIO;
0044 goto out;
0045 }
0046
0047 if (num > buf_size) {
0048 printf("overflowed auxv buffer\n");
0049 rc = -EOVERFLOW;
0050 goto out;
0051 }
0052
0053 rc = 0;
0054 out:
0055 close(fd);
0056 return rc;
0057 }
0058
0059 void *find_auxv_entry(int type, char *auxv)
0060 {
0061 ElfW(auxv_t) *p;
0062
0063 p = (ElfW(auxv_t) *)auxv;
0064
0065 while (p->a_type != AT_NULL) {
0066 if (p->a_type == type)
0067 return p;
0068
0069 p++;
0070 }
0071
0072 return NULL;
0073 }
0074
0075 void *get_auxv_entry(int type)
0076 {
0077 ElfW(auxv_t) *p;
0078
0079 if (read_auxv(auxv, sizeof(auxv)))
0080 return NULL;
0081
0082 p = find_auxv_entry(type, auxv);
0083 if (p)
0084 return (void *)p->a_un.a_val;
0085
0086 return NULL;
0087 }
0088
0089 int pick_online_cpu(void)
0090 {
0091 int ncpus, cpu = -1;
0092 cpu_set_t *mask;
0093 size_t size;
0094
0095 ncpus = get_nprocs_conf();
0096 size = CPU_ALLOC_SIZE(ncpus);
0097 mask = CPU_ALLOC(ncpus);
0098 if (!mask) {
0099 perror("malloc");
0100 return -1;
0101 }
0102
0103 CPU_ZERO_S(size, mask);
0104
0105 if (sched_getaffinity(0, size, mask)) {
0106 perror("sched_getaffinity");
0107 goto done;
0108 }
0109
0110
0111 for (cpu = 8; cpu < ncpus; cpu += 8)
0112 if (CPU_ISSET_S(cpu, size, mask))
0113 goto done;
0114
0115
0116 for (cpu = ncpus - 1; cpu >= 0; cpu--)
0117 if (CPU_ISSET_S(cpu, size, mask))
0118 goto done;
0119
0120 printf("No cpus in affinity mask?!\n");
0121
0122 done:
0123 CPU_FREE(mask);
0124 return cpu;
0125 }
0126
0127 bool is_ppc64le(void)
0128 {
0129 struct utsname uts;
0130 int rc;
0131
0132 errno = 0;
0133 rc = uname(&uts);
0134 if (rc) {
0135 perror("uname");
0136 return false;
0137 }
0138
0139 return strcmp(uts.machine, "ppc64le") == 0;
0140 }
0141
0142 int read_sysfs_file(char *fpath, char *result, size_t result_size)
0143 {
0144 char path[PATH_MAX] = "/sys/";
0145 int rc = -1, fd;
0146
0147 strncat(path, fpath, PATH_MAX - strlen(path) - 1);
0148
0149 if ((fd = open(path, O_RDONLY)) < 0)
0150 return rc;
0151
0152 rc = read(fd, result, result_size);
0153
0154 close(fd);
0155
0156 if (rc < 0)
0157 return rc;
0158
0159 return 0;
0160 }
0161
0162 int read_debugfs_file(char *debugfs_file, int *result)
0163 {
0164 int rc = -1, fd;
0165 char path[PATH_MAX];
0166 char value[16];
0167
0168 strcpy(path, "/sys/kernel/debug/");
0169 strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
0170
0171 if ((fd = open(path, O_RDONLY)) < 0)
0172 return rc;
0173
0174 if ((rc = read(fd, value, sizeof(value))) < 0)
0175 return rc;
0176
0177 value[15] = 0;
0178 *result = atoi(value);
0179 close(fd);
0180
0181 return 0;
0182 }
0183
0184 int write_debugfs_file(char *debugfs_file, int result)
0185 {
0186 int rc = -1, fd;
0187 char path[PATH_MAX];
0188 char value[16];
0189
0190 strcpy(path, "/sys/kernel/debug/");
0191 strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
0192
0193 if ((fd = open(path, O_WRONLY)) < 0)
0194 return rc;
0195
0196 snprintf(value, 16, "%d", result);
0197
0198 if ((rc = write(fd, value, strlen(value))) < 0)
0199 return rc;
0200
0201 close(fd);
0202
0203 return 0;
0204 }
0205
0206 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
0207 int cpu, int group_fd, unsigned long flags)
0208 {
0209 return syscall(__NR_perf_event_open, hw_event, pid, cpu,
0210 group_fd, flags);
0211 }
0212
0213 static void perf_event_attr_init(struct perf_event_attr *event_attr,
0214 unsigned int type,
0215 unsigned long config)
0216 {
0217 memset(event_attr, 0, sizeof(*event_attr));
0218
0219 event_attr->type = type;
0220 event_attr->size = sizeof(struct perf_event_attr);
0221 event_attr->config = config;
0222 event_attr->read_format = PERF_FORMAT_GROUP;
0223 event_attr->disabled = 1;
0224 event_attr->exclude_kernel = 1;
0225 event_attr->exclude_hv = 1;
0226 event_attr->exclude_guest = 1;
0227 }
0228
0229 int perf_event_open_counter(unsigned int type,
0230 unsigned long config, int group_fd)
0231 {
0232 int fd;
0233 struct perf_event_attr event_attr;
0234
0235 perf_event_attr_init(&event_attr, type, config);
0236
0237 fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
0238
0239 if (fd < 0)
0240 perror("perf_event_open() failed");
0241
0242 return fd;
0243 }
0244
0245 int perf_event_enable(int fd)
0246 {
0247 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
0248 perror("error while enabling perf events");
0249 return -1;
0250 }
0251
0252 return 0;
0253 }
0254
0255 int perf_event_disable(int fd)
0256 {
0257 if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
0258 perror("error disabling perf events");
0259 return -1;
0260 }
0261
0262 return 0;
0263 }
0264
0265 int perf_event_reset(int fd)
0266 {
0267 if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
0268 perror("error resetting perf events");
0269 return -1;
0270 }
0271
0272 return 0;
0273 }
0274
0275 int using_hash_mmu(bool *using_hash)
0276 {
0277 char line[128];
0278 FILE *f;
0279 int rc;
0280
0281 f = fopen("/proc/cpuinfo", "r");
0282 FAIL_IF(!f);
0283
0284 rc = 0;
0285 while (fgets(line, sizeof(line), f) != NULL) {
0286 if (!strcmp(line, "MMU : Hash\n") ||
0287 !strcmp(line, "platform : Cell\n") ||
0288 !strcmp(line, "platform : PowerMac\n")) {
0289 *using_hash = true;
0290 goto out;
0291 }
0292
0293 if (strcmp(line, "MMU : Radix\n") == 0) {
0294 *using_hash = false;
0295 goto out;
0296 }
0297 }
0298
0299 rc = -1;
0300 out:
0301 fclose(f);
0302 return rc;
0303 }