Commit f57b05ed532ccf3b3e22878a5678ca10de50ad29

Authored by Jiri Olsa
Committed by Arnaldo Carvalho de Melo
1 parent fc8ed7be73

perf report: Use properly build_id kernel binaries

If we bring the recorded perf data together with kernel binary from another
machine using:

	on server A:
	perf archive

	on server B:
	tar xjvf perf.data.tar.bz2 -C ~/.debug

the build_id kernel dso is not properly recognized during the "perf report"
command on server B.

The reason is, that build_id dsos are added during the session initialization,
while the kernel maps are created during the sample event processing.

The machine__create_kernel_maps functions ends up creating new dso object for
kernel, but it does not check if we already have one added by build_id
processing.

Also the build_id reading ABI quirk added in commit:

 - commit b25114817a73bbd2b84ce9dba02ee1ef8989a947
   perf build-id: Add quirk to deal with perf.data file format breakage

populates the "struct build_id_event::pid" with 0, which
is later interpreted as DEFAULT_GUEST_KERNEL_ID.

This is not always correct, so it's better to guess the pid
value based on the "struct build_id_event::header::misc" value.

- Tested with data generated on x86 kernel version v2.6.34
  and reported back on x86_64 current kernel.
- Not tested for guest kernel case.

Note the problem stays for PERF_RECORD_MMAP events recorded by perf that
does not use proper pid (HOST_KERNEL_ID/DEFAULT_GUEST_KERNEL_ID). They are
misinterpreted within the current perf code. Probably there's not much we
can do about that.

Cc: Avi Kivity <avi@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Yanmin Zhang <yanmin_zhang@linux.intel.com>
Link: http://lkml.kernel.org/r/20110601194346.GB1934@jolsa.brq.redhat.com
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Showing 3 changed files with 42 additions and 27 deletions Side-by-side Diff

tools/perf/util/header.c
... ... @@ -726,7 +726,16 @@
726 726 return -1;
727 727  
728 728 bev.header = old_bev.header;
729   - bev.pid = 0;
  729 +
  730 + /*
  731 + * As the pid is the missing value, we need to fill
  732 + * it properly. The header.misc value give us nice hint.
  733 + */
  734 + bev.pid = HOST_KERNEL_ID;
  735 + if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
  736 + bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
  737 + bev.pid = DEFAULT_GUEST_KERNEL_ID;
  738 +
730 739 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
731 740 __event_process_build_id(&bev, filename, session);
732 741  
tools/perf/util/symbol.c
... ... @@ -2181,32 +2181,27 @@
2181 2181 return ret;
2182 2182 }
2183 2183  
2184   -struct dso *dso__new_kernel(const char *name)
  2184 +static struct dso*
  2185 +dso__kernel_findnew(struct machine *machine, const char *name,
  2186 + const char *short_name, int dso_type)
2185 2187 {
2186   - struct dso *dso = dso__new(name ?: "[kernel.kallsyms]");
  2188 + /*
  2189 + * The kernel dso could be created by build_id processing.
  2190 + */
  2191 + struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2187 2192  
  2193 + /*
  2194 + * We need to run this in all cases, since during the build_id
  2195 + * processing we had no idea this was the kernel dso.
  2196 + */
2188 2197 if (dso != NULL) {
2189   - dso__set_short_name(dso, "[kernel]");
2190   - dso->kernel = DSO_TYPE_KERNEL;
  2198 + dso__set_short_name(dso, short_name);
  2199 + dso->kernel = dso_type;
2191 2200 }
2192 2201  
2193 2202 return dso;
2194 2203 }
2195 2204  
2196   -static struct dso *dso__new_guest_kernel(struct machine *machine,
2197   - const char *name)
2198   -{
2199   - char bf[PATH_MAX];
2200   - struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
2201   - sizeof(bf)));
2202   - if (dso != NULL) {
2203   - dso__set_short_name(dso, "[guest.kernel]");
2204   - dso->kernel = DSO_TYPE_GUEST_KERNEL;
2205   - }
2206   -
2207   - return dso;
2208   -}
2209   -
2210 2205 void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2211 2206 {
2212 2207 char path[PATH_MAX];
2213 2208  
2214 2209  
2215 2210  
2216 2211  
2217 2212  
... ... @@ -2219,24 +2214,36 @@
2219 2214 dso->has_build_id = true;
2220 2215 }
2221 2216  
2222   -static struct dso *machine__create_kernel(struct machine *machine)
  2217 +static struct dso *machine__get_kernel(struct machine *machine)
2223 2218 {
2224 2219 const char *vmlinux_name = NULL;
2225 2220 struct dso *kernel;
2226 2221  
2227 2222 if (machine__is_host(machine)) {
2228 2223 vmlinux_name = symbol_conf.vmlinux_name;
2229   - kernel = dso__new_kernel(vmlinux_name);
  2224 + if (!vmlinux_name)
  2225 + vmlinux_name = "[kernel.kallsyms]";
  2226 +
  2227 + kernel = dso__kernel_findnew(machine, vmlinux_name,
  2228 + "[kernel]",
  2229 + DSO_TYPE_KERNEL);
2230 2230 } else {
  2231 + char bf[PATH_MAX];
  2232 +
2231 2233 if (machine__is_default_guest(machine))
2232 2234 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2233   - kernel = dso__new_guest_kernel(machine, vmlinux_name);
  2235 + if (!vmlinux_name)
  2236 + vmlinux_name = machine__mmap_name(machine, bf,
  2237 + sizeof(bf));
  2238 +
  2239 + kernel = dso__kernel_findnew(machine, vmlinux_name,
  2240 + "[guest.kernel]",
  2241 + DSO_TYPE_GUEST_KERNEL);
2234 2242 }
2235 2243  
2236   - if (kernel != NULL) {
  2244 + if (kernel != NULL && (!kernel->has_build_id))
2237 2245 dso__read_running_kernel_build_id(kernel, machine);
2238   - dsos__add(&machine->kernel_dsos, kernel);
2239   - }
  2246 +
2240 2247 return kernel;
2241 2248 }
2242 2249  
... ... @@ -2340,7 +2347,7 @@
2340 2347  
2341 2348 int machine__create_kernel_maps(struct machine *machine)
2342 2349 {
2343   - struct dso *kernel = machine__create_kernel(machine);
  2350 + struct dso *kernel = machine__get_kernel(machine);
2344 2351  
2345 2352 if (kernel == NULL ||
2346 2353 __machine__create_kernel_maps(machine, kernel) < 0)
tools/perf/util/symbol.h
... ... @@ -155,7 +155,6 @@
155 155 };
156 156  
157 157 struct dso *dso__new(const char *name);
158   -struct dso *dso__new_kernel(const char *name);
159 158 void dso__delete(struct dso *dso);
160 159  
161 160 int dso__name_len(const struct dso *dso);