Home | History | Annotate | Download | only in util
      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 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;
    179 }
    180 
    181 void cpu_map__delete(struct cpu_map *map)
    182 {
    183 	free(map);
    184 }
    185