Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cpumap.c
Go to the documentation of this file.
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 struct cpu_map *cpu_map__read(FILE *file)
42 {
43  struct cpu_map *cpus = NULL;
44  int nr_cpus = 0;
45  int *tmp_cpus = NULL, *tmp;
46  int max_entries = 0;
47  int n, cpu, prev;
48  char sep;
49 
50  sep = 0;
51  prev = -1;
52  for (;;) {
53  n = fscanf(file, "%u%c", &cpu, &sep);
54  if (n <= 0)
55  break;
56  if (prev >= 0) {
57  int new_max = nr_cpus + cpu - prev - 1;
58 
59  if (new_max >= max_entries) {
60  max_entries = new_max + MAX_NR_CPUS / 2;
61  tmp = realloc(tmp_cpus, max_entries * sizeof(int));
62  if (tmp == NULL)
63  goto out_free_tmp;
64  tmp_cpus = tmp;
65  }
66 
67  while (++prev < cpu)
68  tmp_cpus[nr_cpus++] = prev;
69  }
70  if (nr_cpus == max_entries) {
71  max_entries += MAX_NR_CPUS;
72  tmp = realloc(tmp_cpus, max_entries * sizeof(int));
73  if (tmp == NULL)
74  goto out_free_tmp;
75  tmp_cpus = tmp;
76  }
77 
78  tmp_cpus[nr_cpus++] = cpu;
79  if (n == 2 && sep == '-')
80  prev = cpu;
81  else
82  prev = -1;
83  if (n == 1 || sep == '\n')
84  break;
85  }
86 
87  if (nr_cpus > 0)
88  cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
89  else
90  cpus = cpu_map__default_new();
91 out_free_tmp:
92  free(tmp_cpus);
93  return cpus;
94 }
95 
96 static struct cpu_map *cpu_map__read_all_cpu_map(void)
97 {
98  struct cpu_map *cpus = NULL;
99  FILE *onlnf;
100 
101  onlnf = fopen("/sys/devices/system/cpu/online", "r");
102  if (!onlnf)
103  return cpu_map__default_new();
104 
105  cpus = cpu_map__read(onlnf);
106  fclose(onlnf);
107  return cpus;
108 }
109 
110 struct cpu_map *cpu_map__new(const char *cpu_list)
111 {
112  struct cpu_map *cpus = NULL;
113  unsigned long start_cpu, end_cpu = 0;
114  char *p = NULL;
115  int i, nr_cpus = 0;
116  int *tmp_cpus = NULL, *tmp;
117  int max_entries = 0;
118 
119  if (!cpu_list)
120  return cpu_map__read_all_cpu_map();
121 
122  if (!isdigit(*cpu_list))
123  goto out;
124 
125  while (isdigit(*cpu_list)) {
126  p = NULL;
127  start_cpu = strtoul(cpu_list, &p, 0);
128  if (start_cpu >= INT_MAX
129  || (*p != '\0' && *p != ',' && *p != '-'))
130  goto invalid;
131 
132  if (*p == '-') {
133  cpu_list = ++p;
134  p = NULL;
135  end_cpu = strtoul(cpu_list, &p, 0);
136 
137  if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
138  goto invalid;
139 
140  if (end_cpu < start_cpu)
141  goto invalid;
142  } else {
143  end_cpu = start_cpu;
144  }
145 
146  for (; start_cpu <= end_cpu; start_cpu++) {
147  /* check for duplicates */
148  for (i = 0; i < nr_cpus; i++)
149  if (tmp_cpus[i] == (int)start_cpu)
150  goto invalid;
151 
152  if (nr_cpus == max_entries) {
153  max_entries += MAX_NR_CPUS;
154  tmp = realloc(tmp_cpus, max_entries * sizeof(int));
155  if (tmp == NULL)
156  goto invalid;
157  tmp_cpus = tmp;
158  }
159  tmp_cpus[nr_cpus++] = (int)start_cpu;
160  }
161  if (*p)
162  ++p;
163 
164  cpu_list = p;
165  }
166 
167  if (nr_cpus > 0)
168  cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
169  else
170  cpus = cpu_map__default_new();
171 invalid:
172  free(tmp_cpus);
173 out:
174  return cpus;
175 }
176 
177 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
178 {
179  int i;
180  size_t printed = fprintf(fp, "%d cpu%s: ",
181  map->nr, map->nr > 1 ? "s" : "");
182  for (i = 0; i < map->nr; ++i)
183  printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
184 
185  return printed + fprintf(fp, "\n");
186 }
187 
189 {
190  struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
191 
192  if (cpus != NULL) {
193  cpus->nr = 1;
194  cpus->map[0] = -1;
195  }
196 
197  return cpus;
198 }
199 
201 {
202  free(map);
203 }