1 #include <stdlib.h>
2
3 #include "trace-cmd-local.h"
4 #include "trace-local.h"
5
6 /*
7 * Structure to hold the mapping between host and guest.
8 * @self - A pointer back to the guest's mapping (for the host copy to use)
9 * @host_handle - The handle for the host for this mapping.
10 * @guest_handle - The handle for the guest for this mapping.
11 * @guest_vcpu - The vCPU # for this mapping.
12 * @host_pid - The pid of the task on the host that runs when this vCPU executes.
13 * @private - Private data for applications to use.
14 */
15 struct tracecmd_cpu_map {
16 struct tracecmd_cpu_map *self;
17 struct tracecmd_input *host_handle;
18 struct tracecmd_input *guest_handle;
19 int guest_vcpu;
20 int host_pid;
21 void *private;
22 };
23
cmp_map(const void * A,const void * B)24 static int cmp_map(const void *A, const void *B)
25 {
26 const struct tracecmd_cpu_map *a = A;
27 const struct tracecmd_cpu_map *b = B;
28
29 if (a->host_pid < b->host_pid)
30 return -1;
31 return a->host_pid > b->host_pid;
32 }
33
tracecmd_map_vcpus(struct tracecmd_input ** handles,int nr_handles)34 int tracecmd_map_vcpus(struct tracecmd_input **handles, int nr_handles)
35 {
36 struct tracecmd_input *host_handle = handles[0];
37 unsigned long long traceid;
38 struct tracecmd_cpu_map *vcpu_maps = NULL;
39 struct tracecmd_cpu_map *gmap;
40 struct tracecmd_cpu_map *map;
41 const int *cpu_pids;
42 const char *name;
43 int nr_vcpu_maps = 0;
44 int vcpu_count;
45 int mappings = 0;
46 int ret;
47 int i, k;
48
49 /* handles[0] is the host handle, do for each guest handle */
50 for (i = 1; i < nr_handles; i++) {
51 traceid = tracecmd_get_traceid(handles[i]);
52
53 /*
54 * Retrieve the host mapping of the guest for this handle.
55 * cpu_pids is an array of pids that map 1-1 the host vcpus where
56 * cpu_pids[vCPU_num] = host_task_pid
57 */
58 ret = tracecmd_get_guest_cpumap(host_handle, traceid,
59 &name, &vcpu_count, &cpu_pids);
60 if (ret)
61 continue;
62
63 mappings++;
64
65 gmap = calloc(sizeof(*gmap), vcpu_count);
66 if (!gmap)
67 goto fail;
68
69 for (k = 0; k < vcpu_count; k++) {
70 gmap[k].host_handle = handles[0];
71 gmap[k].guest_handle = handles[i];
72 gmap[k].guest_vcpu = k;
73 gmap[k].host_pid = cpu_pids[k];
74 gmap[k].self = &gmap[k];
75 }
76
77 trace_set_guest_map(handles[i], gmap);
78 trace_set_guest_map_cnt(handles[i], vcpu_count);
79
80 /* Update the host mapping of all guests to the host */
81 map = realloc(vcpu_maps, sizeof(*map) * (nr_vcpu_maps + vcpu_count));
82 if (!map)
83 goto fail;
84 memset(map + nr_vcpu_maps, 0, sizeof(*map) * (vcpu_count - nr_vcpu_maps));
85
86 vcpu_maps = map;
87 map += nr_vcpu_maps;
88 nr_vcpu_maps += vcpu_count;
89
90 for (k = 0; k < vcpu_count; k++)
91 map[k] = gmap[k];
92 }
93 if (!vcpu_maps)
94 return 0;
95
96 /* We want to do a binary search via host_pid to find these mappings */
97 qsort(vcpu_maps, nr_vcpu_maps, sizeof(*map), cmp_map);
98
99 trace_set_guest_map(handles[0], vcpu_maps);
100 trace_set_guest_map_cnt(handles[0], nr_vcpu_maps);
101
102 return mappings;
103
104 fail:
105 free(vcpu_maps);
106 return -1;
107 }
108
trace_guest_map_free(struct tracecmd_cpu_map * map)109 __hidden void trace_guest_map_free(struct tracecmd_cpu_map *map)
110 {
111 free(map);
112 }
113
tracecmd_map_find_by_host_pid(struct tracecmd_input * handle,int host_pid)114 struct tracecmd_cpu_map *tracecmd_map_find_by_host_pid(struct tracecmd_input *handle,
115 int host_pid)
116 {
117 struct tracecmd_cpu_map *map;
118 struct tracecmd_cpu_map key;
119 int nr_maps;
120
121 map = trace_get_guest_map(handle);
122 if (!map)
123 return NULL;
124
125 /* The handle could be from the guest, get the host handle */
126 handle = map->host_handle;
127
128 /* And again, get the mapping of the host, as it has all the mappings */
129 map = trace_get_guest_map(handle);
130 if (!map)
131 return NULL;
132
133 nr_maps = trace_get_guest_map_cnt(handle);
134
135 key.host_pid = host_pid;
136
137 map = bsearch(&key, map, nr_maps, sizeof(*map), cmp_map);
138
139 return map ? map->self : NULL;
140 }
141
tracecmd_map_set_private(struct tracecmd_cpu_map * map,void * priv)142 void tracecmd_map_set_private(struct tracecmd_cpu_map *map, void *priv)
143 {
144 /* Only set the guest private */
145 map = map->self;
146 map->private = priv;
147 }
148
tracecmd_map_get_private(struct tracecmd_cpu_map * map)149 void *tracecmd_map_get_private(struct tracecmd_cpu_map *map)
150 {
151 /* Return the guest private */
152 map = map->self;
153 return map->private;
154 }
155
tracecmd_map_get_guest(struct tracecmd_cpu_map * map)156 struct tracecmd_input *tracecmd_map_get_guest(struct tracecmd_cpu_map *map)
157 {
158 return map->guest_handle;
159 }
160
tracecmd_map_get_host_pid(struct tracecmd_cpu_map * map)161 int tracecmd_map_get_host_pid(struct tracecmd_cpu_map *map)
162 {
163 return map->host_pid;
164 }
165
tracecmd_get_cpu_map(struct tracecmd_input * handle,int cpu)166 struct tracecmd_cpu_map *tracecmd_get_cpu_map(struct tracecmd_input *handle, int cpu)
167 {
168 struct tracecmd_cpu_map *map;
169 int cnt;
170
171 map = trace_get_guest_map(handle);
172 /* Make sure it's for the guest handle, as this could be a host handle */
173 map = map->self;
174 cnt = trace_get_guest_map_cnt(map->guest_handle);
175 if (cnt <= cpu)
176 return NULL;
177
178 return map + cpu;
179 }
180