| #include "util.h" | |
| #include "../perf.h" | |
| #include "cpumap.h" | |
| #include <assert.h> | |
| #include <stdio.h> | |
| static struct cpu_map *cpu_map__default_new(void) | |
| { | |
| struct cpu_map *cpus; | |
| int nr_cpus; | |
| nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | |
| if (nr_cpus < 0) | |
| return NULL; | |
| cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int)); | |
| if (cpus != NULL) { | |
| int i; | |
| for (i = 0; i < nr_cpus; ++i) | |
| cpus->map[i] = i; | |
| cpus->nr = nr_cpus; | |
| } | |
| return cpus; | |
| } | |
| static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) | |
| { | |
| size_t payload_size = nr_cpus * sizeof(int); | |
| struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size); | |
| if (cpus != NULL) { | |
| cpus->nr = nr_cpus; | |
| memcpy(cpus->map, tmp_cpus, payload_size); | |
| } | |
| return cpus; | |
| } | |
| static struct cpu_map *cpu_map__read_all_cpu_map(void) | |
| { | |
| struct cpu_map *cpus = NULL; | |
| FILE *onlnf; | |
| int nr_cpus = 0; | |
| int *tmp_cpus = NULL, *tmp; | |
| int max_entries = 0; | |
| int n, cpu, prev; | |
| char sep; | |
| onlnf = fopen("/sys/devices/system/cpu/online", "r"); | |
| if (!onlnf) | |
| return cpu_map__default_new(); | |
| sep = 0; | |
| prev = -1; | |
| for (;;) { | |
| n = fscanf(onlnf, "%u%c", &cpu, &sep); | |
| if (n <= 0) | |
| break; | |
| if (prev >= 0) { | |
| int new_max = nr_cpus + cpu - prev - 1; | |
| if (new_max >= max_entries) { | |
| max_entries = new_max + MAX_NR_CPUS / 2; | |
| tmp = realloc(tmp_cpus, max_entries * sizeof(int)); | |
| if (tmp == NULL) | |
| goto out_free_tmp; | |
| tmp_cpus = tmp; | |
| } | |
| while (++prev < cpu) | |
| tmp_cpus[nr_cpus++] = prev; | |
| } | |
| if (nr_cpus == max_entries) { | |
| max_entries += MAX_NR_CPUS; | |
| tmp = realloc(tmp_cpus, max_entries * sizeof(int)); | |
| if (tmp == NULL) | |
| goto out_free_tmp; | |
| tmp_cpus = tmp; | |
| } | |
| tmp_cpus[nr_cpus++] = cpu; | |
| if (n == 2 && sep == '-') | |
| prev = cpu; | |
| else | |
| prev = -1; | |
| if (n == 1 || sep == '\n') | |
| break; | |
| } | |
| if (nr_cpus > 0) | |
| cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); | |
| else | |
| cpus = cpu_map__default_new(); | |
| out_free_tmp: | |
| free(tmp_cpus); | |
| fclose(onlnf); | |
| return cpus; | |
| } | |
| struct cpu_map *cpu_map__new(const char *cpu_list) | |
| { | |
| struct cpu_map *cpus = NULL; | |
| unsigned long start_cpu, end_cpu = 0; | |
| char *p = NULL; | |
| int i, nr_cpus = 0; | |
| int *tmp_cpus = NULL, *tmp; | |
| int max_entries = 0; | |
| if (!cpu_list) | |
| return cpu_map__read_all_cpu_map(); | |
| if (!isdigit(*cpu_list)) | |
| goto out; | |
| while (isdigit(*cpu_list)) { | |
| p = NULL; | |
| start_cpu = strtoul(cpu_list, &p, 0); | |
| if (start_cpu >= INT_MAX | |
| || (*p != '\0' && *p != ',' && *p != '-')) | |
| goto invalid; | |
| if (*p == '-') { | |
| cpu_list = ++p; | |
| p = NULL; | |
| end_cpu = strtoul(cpu_list, &p, 0); | |
| if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) | |
| goto invalid; | |
| if (end_cpu < start_cpu) | |
| goto invalid; | |
| } else { | |
| end_cpu = start_cpu; | |
| } | |
| for (; start_cpu <= end_cpu; start_cpu++) { | |
| /* check for duplicates */ | |
| for (i = 0; i < nr_cpus; i++) | |
| if (tmp_cpus[i] == (int)start_cpu) | |
| goto invalid; | |
| if (nr_cpus == max_entries) { | |
| max_entries += MAX_NR_CPUS; | |
| tmp = realloc(tmp_cpus, max_entries * sizeof(int)); | |
| if (tmp == NULL) | |
| goto invalid; | |
| tmp_cpus = tmp; | |
| } | |
| tmp_cpus[nr_cpus++] = (int)start_cpu; | |
| } | |
| if (*p) | |
| ++p; | |
| cpu_list = p; | |
| } | |
| if (nr_cpus > 0) | |
| cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); | |
| else | |
| cpus = cpu_map__default_new(); | |
| invalid: | |
| free(tmp_cpus); | |
| out: | |
| return cpus; | |
| } | |
| struct cpu_map *cpu_map__dummy_new(void) | |
| { | |
| struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); | |
| if (cpus != NULL) { | |
| cpus->nr = 1; | |
| cpus->map[0] = -1; | |
| } | |
| return cpus; | |
| } | |
| void cpu_map__delete(struct cpu_map *map) | |
| { | |
| free(map); | |
| } |