Skip to content

Commit 53df2b9

Browse files
captain5050acmel
authored andcommitted
libsymbols kallsyms: Parse using io api
'perf record' will call kallsyms__parse 4 times during startup and process megabytes of data. This changes kallsyms__parse to use the io library rather than fgets to improve performance of the user code by over 8%. Before: Running 'internals/kallsyms-parse' benchmark: Average kallsyms__parse took: 103.988 ms (+- 0.203 ms) After: Running 'internals/kallsyms-parse' benchmark: Average kallsyms__parse took: 95.571 ms (+- 0.006 ms) For a workload like: $ perf record /bin/true Run under 'perf record -e cycles:u -g' the time goes from: Before 30.10% 1.67% perf perf [.] kallsyms__parse After 25.55% 20.04% perf perf [.] kallsyms__parse So a little under 5% of the start-up time is removed. A lot of what remains is on the kernel side, but caching kallsyms within perf would at least impact memory footprint. Committer notes: The internal/kallsyms-parse bench is run using: [root@five ~]# perf bench internals kallsyms-parse # Running 'internals/kallsyms-parse' benchmark: Average kallsyms__parse took: 80.381 ms (+- 0.115 ms) [root@five ~]# And this pre-existing test uses these routines to parse kallsyms and then compare with the info obtained from the matching ELF symtab: [root@five ~]# perf test vmlinux 1: vmlinux symtab matches kallsyms : Ok [root@five ~]# Also we can't remove hex2u64() in this patch as this breaks the build: /usr/bin/ld: /tmp/build/perf/perf-in.o: in function `modules__parse': /home/acme/git/perf/tools/perf/util/symbol.c:607: undefined reference to `hex2u64' /usr/bin/ld: /home/acme/git/perf/tools/perf/util/symbol.c:607: undefined reference to `hex2u64' /usr/bin/ld: /tmp/build/perf/perf-in.o: in function `dso__load_perf_map': /home/acme/git/perf/tools/perf/util/symbol.c:1477: undefined reference to `hex2u64' /usr/bin/ld: /home/acme/git/perf/tools/perf/util/symbol.c:1483: undefined reference to `hex2u64' collect2: error: ld returned 1 exit status Leave it there, move it in the next patch. Signed-off-by: Ian Rogers <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lore.kernel.org/lkml/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 51876bd commit 53df2b9

File tree

2 files changed

+51
-45
lines changed

2 files changed

+51
-45
lines changed

tools/lib/api/io.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#ifndef __API_IO__
88
#define __API_IO__
99

10+
#include <stdlib.h>
11+
#include <unistd.h>
12+
1013
struct io {
1114
/* File descriptor being read/ */
1215
int fd;

tools/lib/symbol/kallsyms.c

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
// SPDX-License-Identifier: GPL-2.0
22
#include "symbol/kallsyms.h"
3+
#include "api/io.h"
34
#include <stdio.h>
4-
#include <stdlib.h>
5+
#include <sys/stat.h>
6+
#include <fcntl.h>
57

68
u8 kallsyms2elf_type(char type)
79
{
810
type = tolower(type);
911
return (type == 't' || type == 'w') ? STT_FUNC : STT_OBJECT;
1012
}
1113

12-
bool kallsyms__is_function(char symbol_type)
13-
{
14-
symbol_type = toupper(symbol_type);
15-
return symbol_type == 'T' || symbol_type == 'W';
16-
}
17-
1814
/*
1915
* While we find nice hex chars, build a long_val.
2016
* Return number of chars processed.
@@ -28,61 +24,68 @@ int hex2u64(const char *ptr, u64 *long_val)
2824
return p - ptr;
2925
}
3026

27+
bool kallsyms__is_function(char symbol_type)
28+
{
29+
symbol_type = toupper(symbol_type);
30+
return symbol_type == 'T' || symbol_type == 'W';
31+
}
32+
33+
static void read_to_eol(struct io *io)
34+
{
35+
int ch;
36+
37+
for (;;) {
38+
ch = io__get_char(io);
39+
if (ch < 0 || ch == '\n')
40+
return;
41+
}
42+
}
43+
3144
int kallsyms__parse(const char *filename, void *arg,
3245
int (*process_symbol)(void *arg, const char *name,
3346
char type, u64 start))
3447
{
35-
char *line = NULL;
36-
size_t n;
37-
int err = -1;
38-
FILE *file = fopen(filename, "r");
39-
40-
if (file == NULL)
41-
goto out_failure;
42-
43-
err = 0;
48+
struct io io;
49+
char bf[BUFSIZ];
50+
int err;
4451

45-
while (!feof(file)) {
46-
u64 start;
47-
int line_len, len;
48-
char symbol_type;
49-
char *symbol_name;
52+
io.fd = open(filename, O_RDONLY, 0);
5053

51-
line_len = getline(&line, &n, file);
52-
if (line_len < 0 || !line)
53-
break;
54+
if (io.fd < 0)
55+
return -1;
5456

55-
line[--line_len] = '\0'; /* \n */
57+
io__init(&io, io.fd, bf, sizeof(bf));
5658

57-
len = hex2u64(line, &start);
59+
err = 0;
60+
while (!io.eof) {
61+
__u64 start;
62+
int ch;
63+
size_t i;
64+
char symbol_type;
65+
char symbol_name[KSYM_NAME_LEN + 1];
5866

59-
/* Skip the line if we failed to parse the address. */
60-
if (!len)
67+
if (io__get_hex(&io, &start) != ' ') {
68+
read_to_eol(&io);
6169
continue;
62-
63-
len++;
64-
if (len + 2 >= line_len)
70+
}
71+
symbol_type = io__get_char(&io);
72+
if (io__get_char(&io) != ' ') {
73+
read_to_eol(&io);
6574
continue;
66-
67-
symbol_type = line[len];
68-
len += 2;
69-
symbol_name = line + len;
70-
len = line_len - len;
71-
72-
if (len >= KSYM_NAME_LEN) {
73-
err = -1;
74-
break;
7575
}
76+
for (i = 0; i < sizeof(symbol_name); i++) {
77+
ch = io__get_char(&io);
78+
if (ch < 0 || ch == '\n')
79+
break;
80+
symbol_name[i] = ch;
81+
}
82+
symbol_name[i] = '\0';
7683

7784
err = process_symbol(arg, symbol_name, symbol_type, start);
7885
if (err)
7986
break;
8087
}
8188

82-
free(line);
83-
fclose(file);
89+
close(io.fd);
8490
return err;
85-
86-
out_failure:
87-
return -1;
8891
}

0 commit comments

Comments
 (0)