diff options
author | Nick Alcock <nick.alcock@oracle.com> | 2021-03-02 15:10:05 +0000 |
---|---|---|
committer | Nick Alcock <nick.alcock@oracle.com> | 2021-03-02 15:10:07 +0000 |
commit | f5060e56338f837f3bb218da50297938d493bacc (patch) | |
tree | e80d03f9496c0fb98bb6b89d69bbd9f3f9076aa9 /libctf/ctf-create.c | |
parent | 478c04a55ee59bf7e7f104c36a08253d15863610 (diff) | |
download | binutils-f5060e56338f837f3bb218da50297938d493bacc.zip binutils-f5060e56338f837f3bb218da50297938d493bacc.tar.gz binutils-f5060e56338f837f3bb218da50297938d493bacc.tar.bz2 |
libctf: add a deduplicator-specific type mapping table
When CTF linking is done, the linker has to track the association
between types in the inputs and types in the outputs. The deduplicator
does this via the cd_output_emission_hashes, which maps from hashes of
types (valid in both the input and output) to the IDs of types in the
specific dict in which the cd_emission_hashes is held. However, the
nondeduplicating linker and ctf_add_type used a different mechanism, a
dedicated hashtab stored in the ctf_link_type_mapping, populated via
ctf_add_type_mapping and queried via the ctf_type_mapping function. To
allow the same functions to be used for variable and symbol population
in both the deduplicating and nondeduplicating linker, the deduplicator
carefully transferred all its input->output mappings into this hashtab
before returning.
This is *expensive*. The number of entries in this hashtab scales as the
number of input types, and unlike the hashing machinery the type mapping
machinery (the only other thing which scales that way) has not been much
optimized.
Now the nondeduplicating linker is gone, we can throw this out, move
the existing type mapping machinery to ctf-create.c and dedicate it to
ctf_add_type alone, and add a new function ctf_dedup_type_mapping which
uses the deduplicator's built-in knowledge of type mappings directly,
without requiring an expensive repopulation phase.
This speeds up a test link of nouveau.ko (a good worst-case candidate
with a lot of types in each of a lot of input files) from 9.11s to 7.15s
in my testing, a speedup of over 20%.
libctf/ChangeLog
2021-03-02 Nick Alcock <nick.alcock@oracle.com>
* ctf-impl.h (ctf_dict_t) <ctf_link_type_mapping>: No longer used
by the nondeduplicating linker.
(ctf_add_type_mapping): Removed, now static.
(ctf_type_mapping): Likewise.
(ctf_dedup_type_mapping): New.
(ctf_dedup_t) <cd_input_nums>: New.
* ctf-dedup.c (ctf_dedup_init): Populate it.
(ctf_dedup_fini): Free it again. Emphasise that this has to be
the last thing called.
(ctf_dedup): Populate it.
(ctf_dedup_populate_type_mapping): Removed.
(ctf_dedup_populate_type_mappings): Likewise.
(ctf_dedup_emit): No longer call it. No longer call
ctf_dedup_fini either.
(ctf_dedup_type_mapping): New.
* ctf-link.c (ctf_unnamed_cuname): New.
(ctf_create_per_cu): Arguments must be non-null now.
(ctf_in_member_cb_arg): Removed.
(ctf_link): No longer populate it. No longer discard the
mapping table.
(ctf_link_deduplicating_one_symtypetab): Use
ctf_dedup_type_mapping, not ctf_type_mapping. Use
ctf_unnamed_cuname.
(ctf_link_one_variable): Likewise. Pass in args individually: no
longer a ctf_variable_iter callback.
(empty_link_type_mapping): Removed.
(ctf_link_deduplicating_variables): Use ctf_variable_next, not
ctf_variable_iter. No longer pack arguments to
ctf_link_one_variable into a struct.
(ctf_link_deduplicating_per_cu): Call ctf_dedup_fini once
all link phases are done.
(ctf_link_deduplicating): Likewise.
(ctf_link_intern_extern_string): Improve comment.
(ctf_add_type_mapping): Migrate...
(ctf_type_mapping): ... these functions...
* ctf-create.c (ctf_add_type_mapping): ... here...
(ctf_type_mapping): ... and make static, for the sole use of
ctf_add_type.
Diffstat (limited to 'libctf/ctf-create.c')
-rw-r--r-- | libctf/ctf-create.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index c01ab7a..d417922 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -2471,6 +2471,101 @@ membadd (const char *name, ctf_id_t type, unsigned long offset, void *arg) return 0; } +/* Record the correspondence between a source and ctf_add_type()-added + destination type: both types are translated into parent type IDs if need be, + so they relate to the actual dictionary they are in. Outside controlled + circumstances (like linking) it is probably not useful to do more than + compare these pointers, since there is nothing stopping the user closing the + source dict whenever they want to. + + Our OOM handling here is just to not do anything, because this is called deep + enough in the call stack that doing anything useful is painfully difficult: + the worst consequence if we do OOM is a bit of type duplication anyway. */ + +static void +ctf_add_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, + ctf_dict_t *dst_fp, ctf_id_t dst_type) +{ + if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent) + src_fp = src_fp->ctf_parent; + + src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type); + + if (LCTF_TYPE_ISPARENT (dst_fp, dst_type) && dst_fp->ctf_parent) + dst_fp = dst_fp->ctf_parent; + + dst_type = LCTF_TYPE_TO_INDEX(dst_fp, dst_type); + + if (dst_fp->ctf_link_type_mapping == NULL) + { + ctf_hash_fun f = ctf_hash_type_key; + ctf_hash_eq_fun e = ctf_hash_eq_type_key; + + if ((dst_fp->ctf_link_type_mapping = ctf_dynhash_create (f, e, free, + NULL)) == NULL) + return; + } + + ctf_link_type_key_t *key; + key = calloc (1, sizeof (struct ctf_link_type_key)); + if (!key) + return; + + key->cltk_fp = src_fp; + key->cltk_idx = src_type; + + /* No OOM checking needed, because if this doesn't work the worst we'll do is + add a few more duplicate types (which will probably run out of memory + anyway). */ + ctf_dynhash_insert (dst_fp->ctf_link_type_mapping, key, + (void *) (uintptr_t) dst_type); +} + +/* Look up a type mapping: return 0 if none. The DST_FP is modified to point to + the parent if need be. The ID returned is from the dst_fp's perspective. */ +static ctf_id_t +ctf_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, ctf_dict_t **dst_fp) +{ + ctf_link_type_key_t key; + ctf_dict_t *target_fp = *dst_fp; + ctf_id_t dst_type = 0; + + if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent) + src_fp = src_fp->ctf_parent; + + src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type); + key.cltk_fp = src_fp; + key.cltk_idx = src_type; + + if (target_fp->ctf_link_type_mapping) + dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping, + &key); + + if (dst_type != 0) + { + dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type, + target_fp->ctf_parent != NULL); + *dst_fp = target_fp; + return dst_type; + } + + if (target_fp->ctf_parent) + target_fp = target_fp->ctf_parent; + else + return 0; + + if (target_fp->ctf_link_type_mapping) + dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping, + &key); + + if (dst_type) + dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type, + target_fp->ctf_parent != NULL); + + *dst_fp = target_fp; + return dst_type; +} + /* The ctf_add_type routine is used to copy a type from a source CTF dictionary to a dynamic destination dictionary. This routine operates recursively by following the source type's links and embedded member types. If the |