aboutsummaryrefslogtreecommitdiffstats
path: root/tools/objtool
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-03-09 01:07:00 -0500
committerIngo Molnar <mingo@kernel.org>2016-03-09 04:48:10 -0500
commit042ba73fe7eb63872ee2d6ac86410052210c1f16 (patch)
tree6f3efe312fc1f2716f0f477a5860a3b6aed3e351 /tools/objtool
parent1698872b5c772aebc5c43ca445cc0a79f12b9fcc (diff)
objtool: Add several performance improvements
Use hash tables for instruction and rela lookups (and keep the linked lists around for sequential access). Also cache the section struct for the "__func_stack_frame_non_standard" section. With this change, "objtool check net/wireless/nl80211.o" goes from: real 0m1.168s user 0m1.163s sys 0m0.005s to: real 0m0.059s user 0m0.042s sys 0m0.017s for a 20x speedup. With the same object, it should be noted that the memory heap usage grew from 8MB to 62MB. Reducing the memory usage is on the TODO list. Reported-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Bernd Petrovitsch <bernd@petrovitsch.priv.at> Cc: Borislav Petkov <bp@alien8.de> Cc: Chris J Arges <chris.j.arges@canonical.com> Cc: Jiri Slaby <jslaby@suse.cz> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michal Marek <mmarek@suse.cz> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Pedro Alves <palves@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/dd0d8e1449506cfa7701b4e7ba73577077c44253.1457502970.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/objtool')
-rw-r--r--tools/objtool/builtin-check.c18
-rw-r--r--tools/objtool/elf.c21
-rw-r--r--tools/objtool/elf.h10
3 files changed, 35 insertions, 14 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index cf1e48dbfa97..bfeee227aaab 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -34,6 +34,8 @@
34#include "arch.h" 34#include "arch.h"
35#include "warn.h" 35#include "warn.h"
36 36
37#include <linux/hashtable.h>
38
37#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 39#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
38 40
39#define STATE_FP_SAVED 0x1 41#define STATE_FP_SAVED 0x1
@@ -42,6 +44,7 @@
42 44
43struct instruction { 45struct instruction {
44 struct list_head list; 46 struct list_head list;
47 struct hlist_node hash;
45 struct section *sec; 48 struct section *sec;
46 unsigned long offset; 49 unsigned long offset;
47 unsigned int len, state; 50 unsigned int len, state;
@@ -61,7 +64,8 @@ struct alternative {
61struct objtool_file { 64struct objtool_file {
62 struct elf *elf; 65 struct elf *elf;
63 struct list_head insn_list; 66 struct list_head insn_list;
64 struct section *rodata; 67 DECLARE_HASHTABLE(insn_hash, 16);
68 struct section *rodata, *whitelist;
65}; 69};
66 70
67const char *objname; 71const char *objname;
@@ -72,7 +76,7 @@ static struct instruction *find_insn(struct objtool_file *file,
72{ 76{
73 struct instruction *insn; 77 struct instruction *insn;
74 78
75 list_for_each_entry(insn, &file->insn_list, list) 79 hash_for_each_possible(file->insn_hash, insn, hash, offset)
76 if (insn->sec == sec && insn->offset == offset) 80 if (insn->sec == sec && insn->offset == offset)
77 return insn; 81 return insn;
78 82
@@ -111,14 +115,12 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file,
111 */ 115 */
112static bool ignore_func(struct objtool_file *file, struct symbol *func) 116static bool ignore_func(struct objtool_file *file, struct symbol *func)
113{ 117{
114 struct section *macro_sec;
115 struct rela *rela; 118 struct rela *rela;
116 struct instruction *insn; 119 struct instruction *insn;
117 120
118 /* check for STACK_FRAME_NON_STANDARD */ 121 /* check for STACK_FRAME_NON_STANDARD */
119 macro_sec = find_section_by_name(file->elf, "__func_stack_frame_non_standard"); 122 if (file->whitelist && file->whitelist->rela)
120 if (macro_sec && macro_sec->rela) 123 list_for_each_entry(rela, &file->whitelist->rela->rela_list, list)
121 list_for_each_entry(rela, &macro_sec->rela->rela_list, list)
122 if (rela->sym->sec == func->sec && 124 if (rela->sym->sec == func->sec &&
123 rela->addend == func->offset) 125 rela->addend == func->offset)
124 return true; 126 return true;
@@ -276,6 +278,7 @@ static int decode_instructions(struct objtool_file *file)
276 return -1; 278 return -1;
277 } 279 }
278 280
281 hash_add(file->insn_hash, &insn->hash, insn->offset);
279 list_add_tail(&insn->list, &file->insn_list); 282 list_add_tail(&insn->list, &file->insn_list);
280 } 283 }
281 } 284 }
@@ -729,6 +732,7 @@ static int decode_sections(struct objtool_file *file)
729{ 732{
730 int ret; 733 int ret;
731 734
735 file->whitelist = find_section_by_name(file->elf, "__func_stack_frame_non_standard");
732 file->rodata = find_section_by_name(file->elf, ".rodata"); 736 file->rodata = find_section_by_name(file->elf, ".rodata");
733 737
734 ret = decode_instructions(file); 738 ret = decode_instructions(file);
@@ -1091,6 +1095,7 @@ static void cleanup(struct objtool_file *file)
1091 free(alt); 1095 free(alt);
1092 } 1096 }
1093 list_del(&insn->list); 1097 list_del(&insn->list);
1098 hash_del(&insn->hash);
1094 free(insn); 1099 free(insn);
1095 } 1100 }
1096 elf_close(file->elf); 1101 elf_close(file->elf);
@@ -1125,6 +1130,7 @@ int cmd_check(int argc, const char **argv)
1125 } 1130 }
1126 1131
1127 INIT_LIST_HEAD(&file.insn_list); 1132 INIT_LIST_HEAD(&file.insn_list);
1133 hash_init(file.insn_hash);
1128 1134
1129 ret = decode_sections(&file); 1135 ret = decode_sections(&file);
1130 if (ret < 0) 1136 if (ret < 0)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 7de243f0a7be..e11f6b69cce6 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -59,7 +59,7 @@ static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
59 struct symbol *sym; 59 struct symbol *sym;
60 60
61 list_for_each_entry(sec, &elf->sections, list) 61 list_for_each_entry(sec, &elf->sections, list)
62 list_for_each_entry(sym, &sec->symbol_list, list) 62 hash_for_each_possible(sec->symbol_hash, sym, hash, idx)
63 if (sym->idx == idx) 63 if (sym->idx == idx)
64 return sym; 64 return sym;
65 65
@@ -82,13 +82,15 @@ struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
82 unsigned int len) 82 unsigned int len)
83{ 83{
84 struct rela *rela; 84 struct rela *rela;
85 unsigned long o;
85 86
86 if (!sec->rela) 87 if (!sec->rela)
87 return NULL; 88 return NULL;
88 89
89 list_for_each_entry(rela, &sec->rela->rela_list, list) 90 for (o = offset; o < offset + len; o++)
90 if (rela->offset >= offset && rela->offset < offset + len) 91 hash_for_each_possible(sec->rela->rela_hash, rela, hash, o)
91 return rela; 92 if (rela->offset == o)
93 return rela;
92 94
93 return NULL; 95 return NULL;
94} 96}
@@ -137,6 +139,8 @@ static int read_sections(struct elf *elf)
137 139
138 INIT_LIST_HEAD(&sec->symbol_list); 140 INIT_LIST_HEAD(&sec->symbol_list);
139 INIT_LIST_HEAD(&sec->rela_list); 141 INIT_LIST_HEAD(&sec->rela_list);
142 hash_init(sec->rela_hash);
143 hash_init(sec->symbol_hash);
140 144
141 list_add_tail(&sec->list, &elf->sections); 145 list_add_tail(&sec->list, &elf->sections);
142 146
@@ -261,6 +265,7 @@ static int read_symbols(struct elf *elf)
261 } 265 }
262 } 266 }
263 list_add(&sym->list, entry); 267 list_add(&sym->list, entry);
268 hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
264 } 269 }
265 270
266 return 0; 271 return 0;
@@ -298,8 +303,6 @@ static int read_relas(struct elf *elf)
298 } 303 }
299 memset(rela, 0, sizeof(*rela)); 304 memset(rela, 0, sizeof(*rela));
300 305
301 list_add_tail(&rela->list, &sec->rela_list);
302
303 if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { 306 if (!gelf_getrela(sec->elf_data, i, &rela->rela)) {
304 perror("gelf_getrela"); 307 perror("gelf_getrela");
305 return -1; 308 return -1;
@@ -315,6 +318,10 @@ static int read_relas(struct elf *elf)
315 symndx, sec->name); 318 symndx, sec->name);
316 return -1; 319 return -1;
317 } 320 }
321
322 list_add_tail(&rela->list, &sec->rela_list);
323 hash_add(sec->rela_hash, &rela->hash, rela->offset);
324
318 } 325 }
319 } 326 }
320 327
@@ -384,10 +391,12 @@ void elf_close(struct elf *elf)
384 list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { 391 list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
385 list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { 392 list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
386 list_del(&sym->list); 393 list_del(&sym->list);
394 hash_del(&sym->hash);
387 free(sym); 395 free(sym);
388 } 396 }
389 list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) { 397 list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) {
390 list_del(&rela->list); 398 list_del(&rela->list);
399 hash_del(&rela->hash);
391 free(rela); 400 free(rela);
392 } 401 }
393 list_del(&sec->list); 402 list_del(&sec->list);
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 57e4653f8383..7f3e00a2f907 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -21,12 +21,15 @@
21#include <stdio.h> 21#include <stdio.h>
22#include <gelf.h> 22#include <gelf.h>
23#include <linux/list.h> 23#include <linux/list.h>
24#include <linux/hashtable.h>
24 25
25struct section { 26struct section {
26 struct list_head list; 27 struct list_head list;
27 GElf_Shdr sh; 28 GElf_Shdr sh;
28 struct list_head symbol_list; 29 struct list_head symbol_list;
30 DECLARE_HASHTABLE(symbol_hash, 8);
29 struct list_head rela_list; 31 struct list_head rela_list;
32 DECLARE_HASHTABLE(rela_hash, 16);
30 struct section *base, *rela; 33 struct section *base, *rela;
31 struct symbol *sym; 34 struct symbol *sym;
32 Elf_Data *elf_data; 35 Elf_Data *elf_data;
@@ -38,10 +41,11 @@ struct section {
38 41
39struct symbol { 42struct symbol {
40 struct list_head list; 43 struct list_head list;
44 struct hlist_node hash;
41 GElf_Sym sym; 45 GElf_Sym sym;
42 struct section *sec; 46 struct section *sec;
43 char *name; 47 char *name;
44 int idx; 48 unsigned int idx;
45 unsigned char bind, type; 49 unsigned char bind, type;
46 unsigned long offset; 50 unsigned long offset;
47 unsigned int len; 51 unsigned int len;
@@ -49,10 +53,11 @@ struct symbol {
49 53
50struct rela { 54struct rela {
51 struct list_head list; 55 struct list_head list;
56 struct hlist_node hash;
52 GElf_Rela rela; 57 GElf_Rela rela;
53 struct symbol *sym; 58 struct symbol *sym;
54 unsigned int type; 59 unsigned int type;
55 int offset; 60 unsigned long offset;
56 int addend; 61 int addend;
57}; 62};
58 63
@@ -62,6 +67,7 @@ struct elf {
62 int fd; 67 int fd;
63 char *name; 68 char *name;
64 struct list_head sections; 69 struct list_head sections;
70 DECLARE_HASHTABLE(rela_hash, 16);
65}; 71};
66 72
67 73