| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 1 | #include "util.h" | 
|  | 2 | #include "../perf.h" | 
|  | 3 | #include "cpumap.h" | 
|  | 4 | #include <assert.h> | 
|  | 5 | #include <stdio.h> | 
|  | 6 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 7 | static struct cpu_map *cpu_map__default_new(void) | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 8 | { | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 9 | struct cpu_map *cpus; | 
|  | 10 | int nr_cpus; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 11 |  | 
|  | 12 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 13 | if (nr_cpus < 0) | 
|  | 14 | return NULL; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 15 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 21 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 22 | cpus->nr = nr_cpus; | 
|  | 23 | } | 
|  | 24 |  | 
|  | 25 | return cpus; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 26 | } | 
|  | 27 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 28 | static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 29 | { | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 44 | FILE *onlnf; | 
|  | 45 | int nr_cpus = 0; | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 46 | int *tmp_cpus = NULL, *tmp; | 
|  | 47 | int max_entries = 0; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 48 | int n, cpu, prev; | 
|  | 49 | char sep; | 
|  | 50 |  | 
|  | 51 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | 
|  | 52 | if (!onlnf) | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 53 | return cpu_map__default_new(); | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 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) { | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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 |  | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 72 | while (++prev < cpu) | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 73 | tmp_cpus[nr_cpus++] = prev; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 74 | } | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 84 | if (n == 2 && sep == '-') | 
|  | 85 | prev = cpu; | 
|  | 86 | else | 
|  | 87 | prev = -1; | 
|  | 88 | if (n == 1 || sep == '\n') | 
|  | 89 | break; | 
|  | 90 | } | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 91 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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; | 
| Paul Mackerras | a12b51c | 2010-03-10 20:36:09 +1100 | [diff] [blame] | 100 | } | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 101 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 102 | struct cpu_map *cpu_map__new(const char *cpu_list) | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 103 | { | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 104 | struct cpu_map *cpus = NULL; | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 105 | unsigned long start_cpu, end_cpu = 0; | 
|  | 106 | char *p = NULL; | 
|  | 107 | int i, nr_cpus = 0; | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 108 | int *tmp_cpus = NULL, *tmp; | 
|  | 109 | int max_entries = 0; | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 110 |  | 
|  | 111 | if (!cpu_list) | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 112 | return cpu_map__read_all_cpu_map(); | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 113 |  | 
|  | 114 | if (!isdigit(*cpu_list)) | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 115 | goto out; | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 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++) | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 141 | if (tmp_cpus[i] == (int)start_cpu) | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 142 | goto invalid; | 
|  | 143 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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; | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 152 | } | 
|  | 153 | if (*p) | 
|  | 154 | ++p; | 
|  | 155 |  | 
|  | 156 | cpu_list = p; | 
|  | 157 | } | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 158 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 159 | if (nr_cpus > 0) | 
|  | 160 | cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); | 
|  | 161 | else | 
|  | 162 | cpus = cpu_map__default_new(); | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 163 | invalid: | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 164 | free(tmp_cpus); | 
|  | 165 | out: | 
|  | 166 | return cpus; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | struct cpu_map *cpu_map__dummy_new(void) | 
|  | 170 | { | 
|  | 171 | struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); | 
|  | 172 |  | 
|  | 173 | if (cpus != NULL) { | 
|  | 174 | cpus->nr = 1; | 
|  | 175 | cpus->map[0] = -1; | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | return cpus; | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 179 | } |