1 #include "util.h" 2 #include "../perf.h" 3 #include "cpumap.h" 4 #include <assert.h> 5 #include <stdio.h> 6 7 static struct cpu_map *cpu_map__default_new(void) 8 { 9 struct cpu_map *cpus; 10 int nr_cpus; 11 12 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 13 if (nr_cpus < 0) 14 return NULL; 15 16 cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int)); 17 if (cpus != NULL) { 18 int i; 19 for (i = 0; i < nr_cpus; ++i) 20 cpus->map[i] = i; 21 22 cpus->nr = nr_cpus; 23 } 24 25 return cpus; 26 } 27 28 static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) 29 { 30 size_t payload_size = nr_cpus * sizeof(int); 31 struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size); 32 33 if (cpus != NULL) { 34 cpus->nr = nr_cpus; 35 memcpy(cpus->map, tmp_cpus, payload_size); 36 } 37 38 return cpus; 39 } 40 41 static struct cpu_map *cpu_map__read_all_cpu_map(void) 42 { 43 struct cpu_map *cpus = NULL; 44 FILE *onlnf; 45 int nr_cpus = 0; 46 int *tmp_cpus = NULL, *tmp; 47 int max_entries = 0; 48 int n, cpu, prev; 49 char sep; 50 51 onlnf = fopen("/sys/devices/system/cpu/online", "r"); 52 if (!onlnf) 53 return cpu_map__default_new(); 54 55 sep = 0; 56 prev = -1; 57 for (;;) { 58 n = fscanf(onlnf, "%u%c", &cpu, &sep); 59 if (n <= 0) 60 break; 61 if (prev >= 0) { 62 int new_max = nr_cpus + cpu - prev - 1; 63 64 if (new_max >= max_entries) { 65 max_entries = new_max + MAX_NR_CPUS / 2; 66 tmp = realloc(tmp_cpus, max_entries * sizeof(int)); 67 if (tmp == NULL) 68 goto out_free_tmp; 69 tmp_cpus = tmp; 70 } 71 72 while (++prev < cpu) 73 tmp_cpus[nr_cpus++] = prev; 74 } 75 if (nr_cpus == max_entries) { 76 max_entries += MAX_NR_CPUS; 77 tmp = realloc(tmp_cpus, max_entries * sizeof(int)); 78 if (tmp == NULL) 79 goto out_free_tmp; 80 tmp_cpus = tmp; 81 } 82 83 tmp_cpus[nr_cpus++] = cpu; 84 if (n == 2 && sep == '-') 85 prev = cpu; 86 else 87 prev = -1; 88 if (n == 1 || sep == '\n') 89 break; 90 } 91 92 if (nr_cpus > 0) 93 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); 94 else 95 cpus = cpu_map__default_new(); 96 out_free_tmp: 97 free(tmp_cpus); 98 fclose(onlnf); 99 return cpus; 100 } 101 102 struct cpu_map *cpu_map__new(const char *cpu_list) 103 { 104 struct cpu_map *cpus = NULL; 105 unsigned long start_cpu, end_cpu = 0; 106 char *p = NULL; 107 int i, nr_cpus = 0; 108 int *tmp_cpus = NULL, *tmp; 109 int max_entries = 0; 110 111 if (!cpu_list) 112 return cpu_map__read_all_cpu_map(); 113 114 if (!isdigit(*cpu_list)) 115 goto out; 116 117 while (isdigit(*cpu_list)) { 118 p = NULL; 119 start_cpu = strtoul(cpu_list, &p, 0); 120 if (start_cpu >= INT_MAX 121 || (*p != '\0' && *p != ',' && *p != '-')) 122 goto invalid; 123 124 if (*p == '-') { 125 cpu_list = ++p; 126 p = NULL; 127 end_cpu = strtoul(cpu_list, &p, 0); 128 129 if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) 130 goto invalid; 131 132 if (end_cpu < start_cpu) 133 goto invalid; 134 } else { 135 end_cpu = start_cpu; 136 } 137 138 for (; start_cpu <= end_cpu; start_cpu++) { 139 /* check for duplicates */ 140 for (i = 0; i < nr_cpus; i++) 141 if (tmp_cpus[i] == (int)start_cpu) 142 goto invalid; 143 144 if (nr_cpus == max_entries) { 145 max_entries += MAX_NR_CPUS; 146 tmp = realloc(tmp_cpus, max_entries * sizeof(int)); 147 if (tmp == NULL) 148 goto invalid; 149 tmp_cpus = tmp; 150 } 151 tmp_cpus[nr_cpus++] = (int)start_cpu; 152 } 153 if (*p) 154 ++p; 155 156 cpu_list = p; 157 } 158 159 if (nr_cpus > 0) 160 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); 161 else 162 cpus = cpu_map__default_new(); 163 invalid: 164 free(tmp_cpus); 165 out: 166 return cpus; 167 } 168 169 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) 170 { 171 int i; 172 size_t printed = fprintf(fp, "%d cpu%s: ", 173 map->nr, map->nr > 1 ? "s" : ""); 174 for (i = 0; i < map->nr; ++i) 175 printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]); 176 177 return printed + fprintf(fp, "\n"); 178 } 179 180 struct cpu_map *cpu_map__dummy_new(void) 181 { 182 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); 183 184 if (cpus != NULL) { 185 cpus->nr = 1; 186 cpus->map[0] = -1; 187 } 188 189 return cpus; 190 } 191 192 void cpu_map__delete(struct cpu_map *map) 193 { 194 free(map); 195 } 196