aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Richter <tmricht@linux.vnet.ibm.com>2017-08-03 09:49:02 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-08-11 15:06:32 -0400
commit9ad4652b66f19a60f07e63b942b80b5c2d7465bf (patch)
tree85c01a0cc992db50a37125d5cd0db4fdeb682233
parentd964b1cdbd94f359f1f65f81440be84ceb45978e (diff)
perf record: Fix wrong size in perf_record_mmap for last kernel module
During work on perf report for s390 I ran into the following issue: 0 0x318 [0x78]: PERF_RECORD_MMAP -1/0: [0x3ff804d6990(0xfffffc007fb2966f) @ 0]: x /lib/modules/4.12.0perf1+/kernel/drivers/s390/net/qeth_l2.ko This is a PERF_RECORD_MMAP entry of the perf.data file with an invalid module size for qeth_l2.ko (the s390 ethernet device driver). Even a mainframe does not have 0xfffffc007fb2966f bytes of main memory. It turned out that this wrong size is created by the perf record command. What happens is this function call sequence from __cmd_record(): perf_session__new(): perf_session__create_kernel_maps(): machine__create_kernel_maps(): machine__create_modules(): Creates map for all loaded kernel modules. modules__parse(): Reads /proc/modules and extracts module name and load address (1st and last column) machine__create_module(): Called for every module found in /proc/modules. Creates a new map for every module found and enters module name and start address into the map. Since the module end address is unknown it is set to zero. This ends up with a kernel module map list sorted by module start addresses. All module end addresses are zero. Last machine__create_kernel_maps() calls function map_groups__fixup_end(). This function iterates through the maps and assigns each map entry's end address the successor map entry start address. The last entry of the map group has no successor, so ~0 is used as end to consume the remaining memory. Later __cmd_record calls function record__synthesize() which in turn calls perf_event__synthesize_kernel_mmap() and perf_event__synthesize_modules() to create PERF_REPORT_MMAP entries into the perf.data file. On s390 this results in the last module qeth_l2.ko (which has highest start address, see module table: [root@s8360047 perf]# cat /proc/modules qeth_l2 86016 1 - Live 0x000003ff804d6000 qeth 266240 1 qeth_l2, Live 0x000003ff80296000 ccwgroup 24576 1 qeth, Live 0x000003ff80218000 vmur 36864 0 - Live 0x000003ff80182000 qdio 143360 2 qeth_l2,qeth, Live 0x000003ff80002000 [root@s8360047 perf]# ) to be the last entry and its map has an end address of ~0. When the PERF_RECORD_MMAP entry is created for kernel module qeth_l2.ko its start address and length is written. The length is calculated in line: event->mmap.len = pos->end - pos->start; and results in 0xffffffffffffffff - 0x3ff804d6990(*) = 0xfffffc007fb2966f (*) On s390 the module start address is actually determined by a __weak function named arch__fix_module_text_start() in machine__create_module(). I think this improvable. We can use the module size (2nd column of /proc/modules) to get each loaded kernel module size and calculate its end address. Only for map entries which do not have a valid end address (end is still zero) we can use the heuristic we have now, that is use successor start address or ~0. Signed-off-by: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com> Reviewed-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Cc: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com> Cc: Zvonko Kosic <zvonko.kosic@de.ibm.com> LPU-Reference: 20170803134902.47207-2-tmricht@linux.vnet.ibm.com Link: http://lkml.kernel.org/n/tip-nmoqij5b5vxx7rq2ckwu8iaj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/machine.c4
-rw-r--r--tools/perf/util/symbol-elf.c2
-rw-r--r--tools/perf/util/symbol.c21
-rw-r--r--tools/perf/util/symbol.h2
4 files changed, 19 insertions, 10 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index d4df353051af..5c8eacaca4f4 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1138,7 +1138,8 @@ int __weak arch__fix_module_text_start(u64 *start __maybe_unused,
1138 return 0; 1138 return 0;
1139} 1139}
1140 1140
1141static int machine__create_module(void *arg, const char *name, u64 start) 1141static int machine__create_module(void *arg, const char *name, u64 start,
1142 u64 size)
1142{ 1143{
1143 struct machine *machine = arg; 1144 struct machine *machine = arg;
1144 struct map *map; 1145 struct map *map;
@@ -1149,6 +1150,7 @@ static int machine__create_module(void *arg, const char *name, u64 start)
1149 map = machine__findnew_module_map(machine, start, name); 1150 map = machine__findnew_module_map(machine, start, name);
1150 if (map == NULL) 1151 if (map == NULL)
1151 return -1; 1152 return -1;
1153 map->end = start + size;
1152 1154
1153 dso__kernel_module_get_build_id(map->dso, machine->root_dir); 1155 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1154 1156
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 7cf18f14e152..98deabb9b47e 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1442,7 +1442,7 @@ static int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci,
1442 1442
1443static int kcore_copy__process_modules(void *arg, 1443static int kcore_copy__process_modules(void *arg,
1444 const char *name __maybe_unused, 1444 const char *name __maybe_unused,
1445 u64 start) 1445 u64 start, u64 size __maybe_unused)
1446{ 1446{
1447 struct kcore_copy_info *kci = arg; 1447 struct kcore_copy_info *kci = arg;
1448 1448
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 971b990557b4..5909ee4c7ade 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -233,7 +233,8 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
233 goto out_unlock; 233 goto out_unlock;
234 234
235 for (next = map__next(curr); next; next = map__next(curr)) { 235 for (next = map__next(curr); next; next = map__next(curr)) {
236 curr->end = next->start; 236 if (!curr->end)
237 curr->end = next->start;
237 curr = next; 238 curr = next;
238 } 239 }
239 240
@@ -241,7 +242,8 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
241 * We still haven't the actual symbols, so guess the 242 * We still haven't the actual symbols, so guess the
242 * last map final address. 243 * last map final address.
243 */ 244 */
244 curr->end = ~0ULL; 245 if (!curr->end)
246 curr->end = ~0ULL;
245 247
246out_unlock: 248out_unlock:
247 pthread_rwlock_unlock(&maps->lock); 249 pthread_rwlock_unlock(&maps->lock);
@@ -552,7 +554,7 @@ void dso__sort_by_name(struct dso *dso, enum map_type type)
552 554
553int modules__parse(const char *filename, void *arg, 555int modules__parse(const char *filename, void *arg,
554 int (*process_module)(void *arg, const char *name, 556 int (*process_module)(void *arg, const char *name,
555 u64 start)) 557 u64 start, u64 size))
556{ 558{
557 char *line = NULL; 559 char *line = NULL;
558 size_t n; 560 size_t n;
@@ -565,8 +567,8 @@ int modules__parse(const char *filename, void *arg,
565 567
566 while (1) { 568 while (1) {
567 char name[PATH_MAX]; 569 char name[PATH_MAX];
568 u64 start; 570 u64 start, size;
569 char *sep; 571 char *sep, *endptr;
570 ssize_t line_len; 572 ssize_t line_len;
571 573
572 line_len = getline(&line, &n, file); 574 line_len = getline(&line, &n, file);
@@ -598,7 +600,11 @@ int modules__parse(const char *filename, void *arg,
598 600
599 scnprintf(name, sizeof(name), "[%s]", line); 601 scnprintf(name, sizeof(name), "[%s]", line);
600 602
601 err = process_module(arg, name, start); 603 size = strtoul(sep + 1, &endptr, 0);
604 if (*endptr != ' ' && *endptr != '\t')
605 continue;
606
607 err = process_module(arg, name, start, size);
602 if (err) 608 if (err)
603 break; 609 break;
604 } 610 }
@@ -945,7 +951,8 @@ static struct module_info *find_module(const char *name,
945 return NULL; 951 return NULL;
946} 952}
947 953
948static int __read_proc_modules(void *arg, const char *name, u64 start) 954static int __read_proc_modules(void *arg, const char *name, u64 start,
955 u64 size __maybe_unused)
949{ 956{
950 struct rb_root *modules = arg; 957 struct rb_root *modules = arg;
951 struct module_info *mi; 958 struct module_info *mi;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index f0b08810d7fa..b221671070e2 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -273,7 +273,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size);
273int sysfs__read_build_id(const char *filename, void *bf, size_t size); 273int sysfs__read_build_id(const char *filename, void *bf, size_t size);
274int modules__parse(const char *filename, void *arg, 274int modules__parse(const char *filename, void *arg,
275 int (*process_module)(void *arg, const char *name, 275 int (*process_module)(void *arg, const char *name,
276 u64 start)); 276 u64 start, u64 size));
277int filename__read_debuglink(const char *filename, char *debuglink, 277int filename__read_debuglink(const char *filename, char *debuglink,
278 size_t size); 278 size_t size);
279 279