utils.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2013-2015, Michael Ellerman, IBM Corp.
  4. */
  5. #define _GNU_SOURCE /* For CPU_ZERO etc. */
  6. #include <elf.h>
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <link.h>
  10. #include <sched.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/ioctl.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. #include <asm/unistd.h>
  21. #include <linux/limits.h>
  22. #include "utils.h"
  23. static char auxv[4096];
  24. int read_auxv(char *buf, ssize_t buf_size)
  25. {
  26. ssize_t num;
  27. int rc, fd;
  28. fd = open("/proc/self/auxv", O_RDONLY);
  29. if (fd == -1) {
  30. perror("open");
  31. return -errno;
  32. }
  33. num = read(fd, buf, buf_size);
  34. if (num < 0) {
  35. perror("read");
  36. rc = -EIO;
  37. goto out;
  38. }
  39. if (num > buf_size) {
  40. printf("overflowed auxv buffer\n");
  41. rc = -EOVERFLOW;
  42. goto out;
  43. }
  44. rc = 0;
  45. out:
  46. close(fd);
  47. return rc;
  48. }
  49. void *find_auxv_entry(int type, char *auxv)
  50. {
  51. ElfW(auxv_t) *p;
  52. p = (ElfW(auxv_t) *)auxv;
  53. while (p->a_type != AT_NULL) {
  54. if (p->a_type == type)
  55. return p;
  56. p++;
  57. }
  58. return NULL;
  59. }
  60. void *get_auxv_entry(int type)
  61. {
  62. ElfW(auxv_t) *p;
  63. if (read_auxv(auxv, sizeof(auxv)))
  64. return NULL;
  65. p = find_auxv_entry(type, auxv);
  66. if (p)
  67. return (void *)p->a_un.a_val;
  68. return NULL;
  69. }
  70. int pick_online_cpu(void)
  71. {
  72. int ncpus, cpu = -1;
  73. cpu_set_t *mask;
  74. size_t size;
  75. ncpus = get_nprocs_conf();
  76. size = CPU_ALLOC_SIZE(ncpus);
  77. mask = CPU_ALLOC(ncpus);
  78. if (!mask) {
  79. perror("malloc");
  80. return -1;
  81. }
  82. CPU_ZERO_S(size, mask);
  83. if (sched_getaffinity(0, size, mask)) {
  84. perror("sched_getaffinity");
  85. goto done;
  86. }
  87. /* We prefer a primary thread, but skip 0 */
  88. for (cpu = 8; cpu < ncpus; cpu += 8)
  89. if (CPU_ISSET_S(cpu, size, mask))
  90. goto done;
  91. /* Search for anything, but in reverse */
  92. for (cpu = ncpus - 1; cpu >= 0; cpu--)
  93. if (CPU_ISSET_S(cpu, size, mask))
  94. goto done;
  95. printf("No cpus in affinity mask?!\n");
  96. done:
  97. CPU_FREE(mask);
  98. return cpu;
  99. }
  100. bool is_ppc64le(void)
  101. {
  102. struct utsname uts;
  103. int rc;
  104. errno = 0;
  105. rc = uname(&uts);
  106. if (rc) {
  107. perror("uname");
  108. return false;
  109. }
  110. return strcmp(uts.machine, "ppc64le") == 0;
  111. }
  112. int read_sysfs_file(char *fpath, char *result, size_t result_size)
  113. {
  114. char path[PATH_MAX] = "/sys/";
  115. int rc = -1, fd;
  116. strncat(path, fpath, PATH_MAX - strlen(path) - 1);
  117. if ((fd = open(path, O_RDONLY)) < 0)
  118. return rc;
  119. rc = read(fd, result, result_size);
  120. close(fd);
  121. if (rc < 0)
  122. return rc;
  123. return 0;
  124. }
  125. int read_debugfs_file(char *debugfs_file, int *result)
  126. {
  127. int rc = -1, fd;
  128. char path[PATH_MAX];
  129. char value[16];
  130. strcpy(path, "/sys/kernel/debug/");
  131. strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
  132. if ((fd = open(path, O_RDONLY)) < 0)
  133. return rc;
  134. if ((rc = read(fd, value, sizeof(value))) < 0)
  135. return rc;
  136. value[15] = 0;
  137. *result = atoi(value);
  138. close(fd);
  139. return 0;
  140. }
  141. int write_debugfs_file(char *debugfs_file, int result)
  142. {
  143. int rc = -1, fd;
  144. char path[PATH_MAX];
  145. char value[16];
  146. strcpy(path, "/sys/kernel/debug/");
  147. strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
  148. if ((fd = open(path, O_WRONLY)) < 0)
  149. return rc;
  150. snprintf(value, 16, "%d", result);
  151. if ((rc = write(fd, value, strlen(value))) < 0)
  152. return rc;
  153. close(fd);
  154. return 0;
  155. }
  156. static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
  157. int cpu, int group_fd, unsigned long flags)
  158. {
  159. return syscall(__NR_perf_event_open, hw_event, pid, cpu,
  160. group_fd, flags);
  161. }
  162. static void perf_event_attr_init(struct perf_event_attr *event_attr,
  163. unsigned int type,
  164. unsigned long config)
  165. {
  166. memset(event_attr, 0, sizeof(*event_attr));
  167. event_attr->type = type;
  168. event_attr->size = sizeof(struct perf_event_attr);
  169. event_attr->config = config;
  170. event_attr->read_format = PERF_FORMAT_GROUP;
  171. event_attr->disabled = 1;
  172. event_attr->exclude_kernel = 1;
  173. event_attr->exclude_hv = 1;
  174. event_attr->exclude_guest = 1;
  175. }
  176. int perf_event_open_counter(unsigned int type,
  177. unsigned long config, int group_fd)
  178. {
  179. int fd;
  180. struct perf_event_attr event_attr;
  181. perf_event_attr_init(&event_attr, type, config);
  182. fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
  183. if (fd < 0)
  184. perror("perf_event_open() failed");
  185. return fd;
  186. }
  187. int perf_event_enable(int fd)
  188. {
  189. if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
  190. perror("error while enabling perf events");
  191. return -1;
  192. }
  193. return 0;
  194. }
  195. int perf_event_disable(int fd)
  196. {
  197. if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
  198. perror("error disabling perf events");
  199. return -1;
  200. }
  201. return 0;
  202. }
  203. int perf_event_reset(int fd)
  204. {
  205. if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
  206. perror("error resetting perf events");
  207. return -1;
  208. }
  209. return 0;
  210. }
  211. int using_hash_mmu(bool *using_hash)
  212. {
  213. char line[128];
  214. FILE *f;
  215. int rc;
  216. f = fopen("/proc/cpuinfo", "r");
  217. FAIL_IF(!f);
  218. rc = 0;
  219. while (fgets(line, sizeof(line), f) != NULL) {
  220. if (!strcmp(line, "MMU : Hash\n") ||
  221. !strcmp(line, "platform : Cell\n") ||
  222. !strcmp(line, "platform : PowerMac\n")) {
  223. *using_hash = true;
  224. goto out;
  225. }
  226. if (strcmp(line, "MMU : Radix\n") == 0) {
  227. *using_hash = false;
  228. goto out;
  229. }
  230. }
  231. rc = -1;
  232. out:
  233. fclose(f);
  234. return rc;
  235. }