| From 3e3f60207399ab29dd55af109e5ae9facc7d8e83 Mon Sep 17 00:00:00 2001 |
| From: Max Filippov <jcmvbkbc@gmail.com> |
| Date: Sat, 28 Mar 2015 08:46:28 +0300 |
| Subject: [PATCH 2/4] xtensa: optimize removed_by_actions |
| |
| The function removed_by_actions iterates through text actions to |
| calculate an offset applied by text actions to a given VMA. Although it |
| has a parameter p_start_action that allows for incremental offset |
| calculation, in many places it's used with p_start_action explicitly set |
| to the first action. After the first relaxation pass when the list of |
| text actions is finalized, an array of offsets sorted by VMA may be used |
| to speed up this function. |
| |
| Original profile: |
| |
| % time self children called name |
| ----------------------------------------- |
| 0.35 0.00 33872/4808961 relax_section_symbols |
| 3.32 0.00 326022/4808961 relax_property_section |
| 12.83 0.00 1259379/4808961 offset_with_removed_text |
| 32.50 0.00 3189688/4808961 translate_reloc |
| 71.5 49.00 0.00 4808961 removed_by_actions |
| ----------------------------------------- |
| |
| Same data, after optimization: |
| |
| % time self children called name |
| ----------------------------------------- |
| 0.00 0.00 33872/4808537 relax_section_symbols |
| 0.01 0.00 326022/4808537 relax_property_section |
| 0.05 0.00 1258955/4808537 offset_with_removed_text_map |
| 0.13 0.00 3189688/4808537 translate_reloc |
| 1.0 0.20 0.00 4808537 removed_by_actions_map |
| 0.00 0.00 120/120 map_removal_by_action |
| ----------------------------------------- |
| |
| 2015-04-01 Max Filippov <jcmvbkbc@gmail.com> |
| bfd/ |
| * elf32-xtensa.c (removal_by_action_entry_struct, |
| removal_by_action_map_struct): new structures. |
| (removal_by_action_entry, removal_by_action_map): new typedefs. |
| (text_action_list_struct): add new field: map. |
| (map_removal_by_action, removed_by_actions_map, |
| offset_with_removed_text_map): new functions. |
| (relax_section): replace offset_with_removed_text with |
| offset_with_removed_text_map. |
| (translate_reloc, relax_property_section, relax_section_symbols): |
| replace removed_by_actions with removed_by_actions_map. |
| |
| Backported from: 071aa5c98a31c966f5fbfc573fcee61350fd1936 |
| Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> |
| --- |
| bfd/elf32-xtensa.c | 181 +++++++++++++++++++++++++++++++++++++++++++++-------- |
| 1 file changed, 156 insertions(+), 25 deletions(-) |
| |
| diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c |
| index 872370b..21b2871 100644 |
| --- a/bfd/elf32-xtensa.c |
| +++ b/bfd/elf32-xtensa.c |
| @@ -5420,11 +5420,28 @@ struct text_action_struct |
| text_action *next; |
| }; |
| |
| +struct removal_by_action_entry_struct |
| +{ |
| + bfd_vma offset; |
| + int removed; |
| + int eq_removed; |
| + int eq_removed_before_fill; |
| +}; |
| +typedef struct removal_by_action_entry_struct removal_by_action_entry; |
| + |
| +struct removal_by_action_map_struct |
| +{ |
| + unsigned n_entries; |
| + removal_by_action_entry *entry; |
| +}; |
| +typedef struct removal_by_action_map_struct removal_by_action_map; |
| + |
| |
| /* List of all of the actions taken on a text section. */ |
| struct text_action_list_struct |
| { |
| text_action *head; |
| + removal_by_action_map map; |
| }; |
| |
| |
| @@ -5636,6 +5653,101 @@ action_list_count (text_action_list *action_list) |
| return count; |
| } |
| |
| +static void |
| +map_removal_by_action (text_action_list *action_list) |
| +{ |
| + text_action *r; |
| + int removed = 0; |
| + removal_by_action_map map; |
| + bfd_boolean eq_complete; |
| + |
| + map.n_entries = 0; |
| + map.entry = bfd_malloc (action_list_count (action_list) * |
| + sizeof (removal_by_action_entry)); |
| + eq_complete = FALSE; |
| + |
| + for (r = action_list->head; r;) |
| + { |
| + removal_by_action_entry *ientry = map.entry + map.n_entries; |
| + |
| + if (map.n_entries && (ientry - 1)->offset == r->offset) |
| + { |
| + --ientry; |
| + } |
| + else |
| + { |
| + ++map.n_entries; |
| + eq_complete = FALSE; |
| + ientry->offset = r->offset; |
| + ientry->eq_removed_before_fill = removed; |
| + } |
| + |
| + if (!eq_complete) |
| + { |
| + if (r->action != ta_fill || r->removed_bytes >= 0) |
| + { |
| + ientry->eq_removed = removed; |
| + eq_complete = TRUE; |
| + } |
| + else |
| + ientry->eq_removed = removed + r->removed_bytes; |
| + } |
| + |
| + removed += r->removed_bytes; |
| + ientry->removed = removed; |
| + r = r->next; |
| + } |
| + action_list->map = map; |
| +} |
| + |
| +static int |
| +removed_by_actions_map (text_action_list *action_list, bfd_vma offset, |
| + bfd_boolean before_fill) |
| +{ |
| + unsigned a, b; |
| + |
| + if (!action_list->map.entry) |
| + map_removal_by_action (action_list); |
| + |
| + if (!action_list->map.n_entries) |
| + return 0; |
| + |
| + a = 0; |
| + b = action_list->map.n_entries; |
| + |
| + while (b - a > 1) |
| + { |
| + unsigned c = (a + b) / 2; |
| + |
| + if (action_list->map.entry[c].offset <= offset) |
| + a = c; |
| + else |
| + b = c; |
| + } |
| + |
| + if (action_list->map.entry[a].offset < offset) |
| + { |
| + return action_list->map.entry[a].removed; |
| + } |
| + else if (action_list->map.entry[a].offset == offset) |
| + { |
| + return before_fill ? |
| + action_list->map.entry[a].eq_removed_before_fill : |
| + action_list->map.entry[a].eq_removed; |
| + } |
| + else |
| + { |
| + return 0; |
| + } |
| +} |
| + |
| +static bfd_vma |
| +offset_with_removed_text_map (text_action_list *action_list, bfd_vma offset) |
| +{ |
| + int removed = removed_by_actions_map (action_list, offset, FALSE); |
| + return offset - removed; |
| +} |
| + |
| |
| /* The find_insn_action routine will only find non-fill actions. */ |
| |
| @@ -5909,6 +6021,9 @@ init_xtensa_relax_info (asection *sec) |
| |
| relax_info->action_list.head = NULL; |
| |
| + relax_info->action_list.map.n_entries = 0; |
| + relax_info->action_list.map.entry = NULL; |
| + |
| relax_info->fix_list = NULL; |
| relax_info->fix_array = NULL; |
| relax_info->fix_array_count = 0; |
| @@ -9218,7 +9333,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) |
| if (elf_hash_table (link_info)->dynamic_sections_created) |
| shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); |
| irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); |
| - irel->r_offset = offset_with_removed_text |
| + irel->r_offset = offset_with_removed_text_map |
| (&relax_info->action_list, irel->r_offset); |
| continue; |
| } |
| @@ -9255,7 +9370,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) |
| } |
| } |
| |
| - source_offset = offset_with_removed_text |
| + source_offset = offset_with_removed_text_map |
| (&relax_info->action_list, irel->r_offset); |
| irel->r_offset = source_offset; |
| } |
| @@ -9352,7 +9467,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) |
| break; |
| } |
| |
| - new_end_offset = offset_with_removed_text |
| + new_end_offset = offset_with_removed_text_map |
| (&target_relax_info->action_list, |
| r_rel.target_offset + diff_value); |
| diff_value = new_end_offset - new_reloc.target_offset; |
| @@ -9750,7 +9865,6 @@ translate_reloc (const r_reloc *orig_rel, r_reloc *new_rel, asection *sec) |
| xtensa_relax_info *relax_info; |
| removed_literal *removed; |
| bfd_vma target_offset, base_offset; |
| - text_action *act; |
| |
| *new_rel = *orig_rel; |
| |
| @@ -9803,19 +9917,26 @@ translate_reloc (const r_reloc *orig_rel, r_reloc *new_rel, asection *sec) |
| offset. */ |
| |
| base_offset = r_reloc_get_target_offset (new_rel) - new_rel->rela.r_addend; |
| - act = relax_info->action_list.head; |
| if (base_offset <= target_offset) |
| { |
| - int base_removed = removed_by_actions (&act, base_offset, FALSE); |
| - int addend_removed = removed_by_actions (&act, target_offset, FALSE); |
| + int base_removed = removed_by_actions_map (&relax_info->action_list, |
| + base_offset, FALSE); |
| + int addend_removed = removed_by_actions_map (&relax_info->action_list, |
| + target_offset, FALSE) - |
| + base_removed; |
| + |
| new_rel->target_offset = target_offset - base_removed - addend_removed; |
| new_rel->rela.r_addend -= addend_removed; |
| } |
| else |
| { |
| /* Handle a negative addend. The base offset comes first. */ |
| - int tgt_removed = removed_by_actions (&act, target_offset, FALSE); |
| - int addend_removed = removed_by_actions (&act, base_offset, FALSE); |
| + int tgt_removed = removed_by_actions_map (&relax_info->action_list, |
| + target_offset, FALSE); |
| + int addend_removed = removed_by_actions_map (&relax_info->action_list, |
| + base_offset, FALSE) - |
| + tgt_removed; |
| + |
| new_rel->target_offset = target_offset - tgt_removed; |
| new_rel->rela.r_addend += addend_removed; |
| } |
| @@ -10138,9 +10259,10 @@ relax_property_section (bfd *abfd, |
| bfd_vma old_offset = val.r_rel.target_offset; |
| bfd_vma new_offset; |
| long old_size, new_size; |
| - text_action *act = target_relax_info->action_list.head; |
| - new_offset = old_offset - |
| - removed_by_actions (&act, old_offset, FALSE); |
| + int removed_by_old_offset = |
| + removed_by_actions_map (&target_relax_info->action_list, |
| + old_offset, FALSE); |
| + new_offset = old_offset - removed_by_old_offset; |
| |
| /* Assert that we are not out of bounds. */ |
| old_size = bfd_get_32 (abfd, size_p); |
| @@ -10164,9 +10286,10 @@ relax_property_section (bfd *abfd, |
| |
| /* Recompute the new_offset, but this time don't |
| include any fill inserted by relaxation. */ |
| - act = target_relax_info->action_list.head; |
| - new_offset = old_offset - |
| - removed_by_actions (&act, old_offset, TRUE); |
| + removed_by_old_offset = |
| + removed_by_actions_map (&target_relax_info->action_list, |
| + old_offset, TRUE); |
| + new_offset = old_offset - removed_by_old_offset; |
| |
| /* If it is not unreachable and we have not yet |
| seen an unreachable at this address, place it |
| @@ -10182,8 +10305,12 @@ relax_property_section (bfd *abfd, |
| } |
| } |
| else |
| - new_size -= |
| - removed_by_actions (&act, old_offset + old_size, TRUE); |
| + { |
| + int removed_by_old_offset_size = |
| + removed_by_actions_map (&target_relax_info->action_list, |
| + old_offset + old_size, TRUE); |
| + new_size -= removed_by_old_offset_size - removed_by_old_offset; |
| + } |
| |
| if (new_size != old_size) |
| { |
| @@ -10441,14 +10568,16 @@ relax_section_symbols (bfd *abfd, asection *sec) |
| |
| if (isym->st_shndx == sec_shndx) |
| { |
| - text_action *act = relax_info->action_list.head; |
| bfd_vma orig_addr = isym->st_value; |
| + int removed = removed_by_actions_map (&relax_info->action_list, |
| + orig_addr, FALSE); |
| |
| - isym->st_value -= removed_by_actions (&act, orig_addr, FALSE); |
| - |
| + isym->st_value -= removed; |
| if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC) |
| isym->st_size -= |
| - removed_by_actions (&act, orig_addr + isym->st_size, FALSE); |
| + removed_by_actions_map (&relax_info->action_list, |
| + orig_addr + isym->st_size, FALSE) - |
| + removed; |
| } |
| } |
| |
| @@ -10466,15 +10595,17 @@ relax_section_symbols (bfd *abfd, asection *sec) |
| || sym_hash->root.type == bfd_link_hash_defweak) |
| && sym_hash->root.u.def.section == sec) |
| { |
| - text_action *act = relax_info->action_list.head; |
| bfd_vma orig_addr = sym_hash->root.u.def.value; |
| + int removed = removed_by_actions_map (&relax_info->action_list, |
| + orig_addr, FALSE); |
| |
| - sym_hash->root.u.def.value -= |
| - removed_by_actions (&act, orig_addr, FALSE); |
| + sym_hash->root.u.def.value -= removed; |
| |
| if (sym_hash->type == STT_FUNC) |
| sym_hash->size -= |
| - removed_by_actions (&act, orig_addr + sym_hash->size, FALSE); |
| + removed_by_actions_map (&relax_info->action_list, |
| + orig_addr + sym_hash->size, FALSE) - |
| + removed; |
| } |
| } |
| |
| -- |
| 1.8.1.4 |
| |