| 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 |  | 
| Arnaldo Carvalho de Melo | 9ae7d33 | 2012-01-19 14:07:23 -0200 | [diff] [blame] | 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 |  | 
| Arnaldo Carvalho de Melo | 60d567e | 2011-01-03 17:49:48 -0200 | [diff] [blame] | 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; | 
| Stephane Eranian | c45c6ea | 2010-05-28 12:00:01 +0200 | [diff] [blame] | 190 | } | 
| Arnaldo Carvalho de Melo | 915fce2 | 2011-01-14 16:19:12 -0200 | [diff] [blame] | 191 |  | 
 | 192 | void cpu_map__delete(struct cpu_map *map) | 
 | 193 | { | 
 | 194 | 	free(map); | 
 | 195 | } |