cpu.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /* cpu.c
  2. * Parse CPU-related files.
  3. */
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <dirent.h>
  9. #include <limits.h>
  10. #include <ctype.h>
  11. #include <unistd.h>
  12. #include "lub/list.h"
  13. #include "cpumask.h"
  14. #include "cpu.h"
  15. #include "irq.h"
  16. int cpu_list_compare(const void *first, const void *second)
  17. {
  18. const cpu_t *f = (const cpu_t *)first;
  19. const cpu_t *s = (const cpu_t *)second;
  20. return (f->id - s->id);
  21. }
  22. int cpu_list_compare_len(const void *first, const void *second)
  23. {
  24. const cpu_t *f = (const cpu_t *)first;
  25. const cpu_t *s = (const cpu_t *)second;
  26. return (lub_list_len(f->irqs) - lub_list_len(s->irqs));
  27. }
  28. static cpu_t * cpu_new(unsigned int id)
  29. {
  30. cpu_t *new;
  31. if (!(new = malloc(sizeof(*new))))
  32. return NULL;
  33. new->id = id;
  34. new->old_load_all = 0;
  35. new->old_load_irq = 0;
  36. new->old_load = 0;
  37. new->load = 0;
  38. new->irqs = lub_list_new(irq_list_compare);
  39. cpus_init(new->cpumask);
  40. cpus_clear(new->cpumask);
  41. cpu_set(new->id, new->cpumask);
  42. return new;
  43. }
  44. static void cpu_free(cpu_t *cpu)
  45. {
  46. lub_list_node_t *node;
  47. while ((node = lub_list__get_tail(cpu->irqs))) {
  48. lub_list_del(cpu->irqs, node);
  49. lub_list_node_free(node);
  50. }
  51. lub_list_free(cpu->irqs);
  52. cpus_free(cpu->cpumask);
  53. free(cpu);
  54. }
  55. /* Search for CPU with specified package and core IDs.
  56. The second CPU with the same IDs is a thread of Hyper Threading.
  57. We don't want to use HT for IRQ balancing. */
  58. static cpu_t * cpu_list_search_ht(lub_list_t *cpus,
  59. unsigned int package_id, unsigned int core_id,
  60. cpumask_t *thread_siblings)
  61. {
  62. lub_list_node_t *iter;
  63. /* Check if current CPU has thread siblings */
  64. /* The CPUs without thread siblings has no hyper
  65. threading. For example some AMD processors has
  66. two CPUs with the same package and core ids but
  67. has no thread siblings. Don't consider such CPUs as
  68. a hyper threading. */
  69. if (cpus_weight(*thread_siblings) < 2)
  70. return NULL;
  71. for (iter = lub_list_iterator_init(cpus); iter;
  72. iter = lub_list_iterator_next(iter)) {
  73. cpu_t *cpu;
  74. cpu = (cpu_t *)lub_list_node__get_data(iter);
  75. if (cpu->package_id != package_id)
  76. continue;
  77. if (cpu->core_id != core_id)
  78. continue;
  79. return cpu;
  80. }
  81. return NULL;
  82. }
  83. cpu_t * cpu_list_search(lub_list_t *cpus, unsigned int id)
  84. {
  85. lub_list_node_t *node;
  86. cpu_t search;
  87. search.id = id;
  88. node = lub_list_search(cpus, &search);
  89. if (!node)
  90. return NULL;
  91. return (cpu_t *)lub_list_node__get_data(node);
  92. }
  93. static cpu_t * cpu_list_add(lub_list_t *cpus, cpu_t *cpu)
  94. {
  95. cpu_t *old = cpu_list_search(cpus, cpu->id);
  96. if (old) /* CPU already exists. May be renew some fields later */
  97. return old;
  98. lub_list_add(cpus, cpu);
  99. return cpu;
  100. }
  101. int cpu_list_free(lub_list_t *cpus)
  102. {
  103. lub_list_node_t *iter;
  104. while ((iter = lub_list__get_head(cpus))) {
  105. cpu_t *cpu;
  106. cpu = (cpu_t *)lub_list_node__get_data(iter);
  107. cpu_free(cpu);
  108. lub_list_del(cpus, iter);
  109. lub_list_node_free(iter);
  110. }
  111. lub_list_free(cpus);
  112. return 0;
  113. }
  114. /* Show CPU information */
  115. static void show_cpu_info(cpu_t *cpu)
  116. {
  117. char buf[NR_CPUS + 1];
  118. cpumask_scnprintf(buf, sizeof(buf), cpu->cpumask);
  119. buf[sizeof(buf) - 1] = '\0';
  120. printf("CPU %d package %d core %d mask %s\n", cpu->id, cpu->package_id, cpu->core_id, buf);
  121. }
  122. /* Show CPU list */
  123. int show_cpus(lub_list_t *cpus)
  124. {
  125. lub_list_node_t *iter;
  126. for (iter = lub_list_iterator_init(cpus); iter;
  127. iter = lub_list_iterator_next(iter)) {
  128. cpu_t *cpu;
  129. cpu = (cpu_t *)lub_list_node__get_data(iter);
  130. show_cpu_info(cpu);
  131. }
  132. return 0;
  133. }
  134. /* Search for CPUs */
  135. int scan_cpus(lub_list_t *cpus, int ht)
  136. {
  137. FILE *fd;
  138. char path[PATH_MAX];
  139. unsigned int id;
  140. unsigned int package_id;
  141. unsigned int core_id;
  142. cpu_t *new;
  143. char *str = NULL;
  144. size_t sz;
  145. cpumask_t thread_siblings;
  146. cpus_init(thread_siblings);
  147. for (id = 0; id < NR_CPUS; id++) {
  148. snprintf(path, sizeof(path), "%s/cpu%d", SYSFS_CPU_PATH, id);
  149. path[sizeof(path) - 1] = '\0';
  150. if (access(path, F_OK))
  151. break;
  152. /* Try to get package_id */
  153. snprintf(path, sizeof(path),
  154. "%s/cpu%d/topology/physical_package_id",
  155. SYSFS_CPU_PATH, id);
  156. path[sizeof(path) - 1] = '\0';
  157. if (!(fd = fopen(path, "r")))
  158. continue;
  159. if (fscanf(fd, "%u", &package_id) < 0) {
  160. fclose(fd);
  161. continue;
  162. }
  163. fclose(fd);
  164. /* Try to get core_id */
  165. snprintf(path, sizeof(path), "%s/cpu%d/topology/core_id",
  166. SYSFS_CPU_PATH, id);
  167. path[sizeof(path) - 1] = '\0';
  168. if (!(fd = fopen(path, "r")))
  169. continue;
  170. if (fscanf(fd, "%u", &core_id) < 0) {
  171. fclose(fd);
  172. continue;
  173. }
  174. fclose(fd);
  175. /* Get thread siblings */
  176. cpus_clear(thread_siblings);
  177. cpu_set(id, thread_siblings);
  178. snprintf(path, sizeof(path), "%s/cpu%d/topology/thread_siblings",
  179. SYSFS_CPU_PATH, id);
  180. path[sizeof(path) - 1] = '\0';
  181. if ((fd = fopen(path, "r"))) {
  182. if (getline(&str, &sz, fd) >= 0)
  183. cpumask_parse_user(str, strlen(str), thread_siblings);
  184. fclose(fd);
  185. }
  186. /* Don't use second thread of Hyper Threading */
  187. if (!ht && cpu_list_search_ht(cpus, package_id, core_id,
  188. &thread_siblings))
  189. continue;
  190. new = cpu_new(id);
  191. new->package_id = package_id;
  192. new->core_id = core_id;
  193. cpu_list_add(cpus, new);
  194. }
  195. cpus_free(thread_siblings);
  196. free(str);
  197. return 0;
  198. }