diff options
author | Nick Alcock <nick.alcock@oracle.com> | 2019-06-27 13:51:10 +0100 |
---|---|---|
committer | Nick Alcock <nick.alcock@oracle.com> | 2019-07-01 11:05:59 +0100 |
commit | f5e9c9bde04ae52b92027b78c9ca20055f1afb78 (patch) | |
tree | 99f8b4e2e938d6195ca0ad6842e2a3a9676da6bb /libctf/ctf-impl.h | |
parent | 9658dc39630b8ac4e849fb529a53902da5fc2b1f (diff) | |
download | gdb-f5e9c9bde04ae52b92027b78c9ca20055f1afb78.zip gdb-f5e9c9bde04ae52b92027b78c9ca20055f1afb78.tar.gz gdb-f5e9c9bde04ae52b92027b78c9ca20055f1afb78.tar.bz2 |
libctf: deduplicate and sort the string table
ctf.h states:
> [...] the CTF string table does not contain any duplicated strings.
Unfortunately this is entirely untrue: libctf has before now made no
attempt whatsoever to deduplicate the string table. It computes the
string table's length on the fly as it adds new strings to the dynamic
CTF file, and ctf_update() just writes each string to the table and
notes the current write position as it traverses the dynamic CTF file's
data structures and builds the final CTF buffer. There is no global
view of the strings and no deduplication.
Fix this by erasing the ctf_dtvstrlen dead-reckoning length, and adding
a new dynhash table ctf_str_atoms that maps unique strings to a list
of references to those strings: a reference is a simple uint32_t * to
some value somewhere in the under-construction CTF buffer that needs
updating to note the string offset when the strtab is laid out.
Adding a string is now a simple matter of calling ctf_str_add_ref(),
which adds a new atom to the atoms table, if one doesn't already exist,
and adding the location of the reference to this atom to the refs list
attached to the atom: this works reliably as long as one takes care to
only call ctf_str_add_ref() once the final location of the offset is
known (so you can't call it on a temporary structure and then memcpy()
that structure into place in the CTF buffer, because the ref will still
point to the old location: ctf_update() changes accordingly).
Generating the CTF string table is a matter of calling
ctf_str_write_strtab(), which counts the length and number of elements
in the atoms table using the ctf_dynhash_iter() function we just added,
populating an array of pointers into the atoms table and sorting it into
order (to help compressors), then traversing this table and emitting it,
updating the refs to each atom as we go. The only complexity here is
arranging to keep the null string at offset zero, since a lot of code in
libctf depends on being able to leave strtab references at 0 to indicate
'no name'. Once the table is constructed and the refs updated, we know
how long it is, so we can realloc() the partial CTF buffer we allocated
earlier and can copy the table on to the end of it (and purge the refs
because they're not needed any more and have been invalidated by the
realloc() call in any case).
The net effect of all this is a reduction in uncompressed strtab sizes
of about 30% (perhaps a quarter to a half of all strings across the
Linux kernel are eliminated as duplicates). Of course, duplicated
strings are highly redundant, so the space saving after compression is
only about 20%: when the other non-strtab sections are factored in, CTF
sizes shrink by about 10%.
No change in externally-visible API or file format (other than the
reduction in pointless redundancy).
libctf/
* ctf-impl.h: (struct ctf_strs_writable): New, non-const version of
struct ctf_strs.
(struct ctf_dtdef): Note that dtd_data.ctt_name is unpopulated.
(struct ctf_str_atom): New, disambiguated single string.
(struct ctf_str_atom_ref): New, points to some other location that
references this string's offset.
(struct ctf_file): New members ctf_str_atoms and ctf_str_num_refs.
Remove member ctf_dtvstrlen: we no longer track the total strlen
as we add strings.
(ctf_str_create_atoms): Declare new function in ctf-string.c.
(ctf_str_free_atoms): Likewise.
(ctf_str_add): Likewise.
(ctf_str_add_ref): Likewise.
(ctf_str_purge_refs): Likewise.
(ctf_str_write_strtab): Likewise.
(ctf_realloc): Declare new function in ctf-util.c.
* ctf-open.c (ctf_bufopen): Create the atoms table.
(ctf_file_close): Destroy it.
* ctf-create.c (ctf_update): Copy-and-free it on update. No longer
special-case the position of the parname string. Construct the
strtab by calling ctf_str_add_ref and ctf_str_write_strtab after the
rest of each buffer element is constructed, not via open-coding:
realloc the CTF buffer and append the strtab to it. No longer
maintain ctf_dtvstrlen. Sort the variable entry table later, after
strtab construction.
(ctf_copy_membnames): Remove: integrated into ctf_copy_{s,l,e}members.
(ctf_copy_smembers): Drop the string offset: call ctf_str_add_ref
after buffer element construction instead.
(ctf_copy_lmembers): Likewise.
(ctf_copy_emembers): Likewise.
(ctf_create): No longer maintain the ctf_dtvstrlen.
(ctf_dtd_delete): Likewise.
(ctf_dvd_delete): Likewise.
(ctf_add_generic): Likewise.
(ctf_add_enumerator): Likewise.
(ctf_add_member_offset): Likewise.
(ctf_add_variable): Likewise.
(membadd): Likewise.
* ctf-util.c (ctf_realloc): New, wrapper around realloc that aborts
if there are active ctf_str_num_refs.
(ctf_strraw): Move to ctf-string.c.
(ctf_strptr): Likewise.
* ctf-string.c: New file, strtab manipulation.
* Makefile.am (libctf_a_SOURCES): Add it.
* Makefile.in: Regenerate.
Diffstat (limited to 'libctf/ctf-impl.h')
-rw-r--r-- | libctf/ctf-impl.h | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 2601e1b..b51118c 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -71,6 +71,12 @@ typedef struct ctf_strs size_t cts_len; /* Size of string table in bytes. */ } ctf_strs_t; +typedef struct ctf_strs_writable +{ + char *cts_strs; /* Base address of string table. */ + size_t cts_len; /* Size of string table in bytes. */ +} ctf_strs_writable_t; + typedef struct ctf_dmodel { const char *ctd_name; /* Data model name. */ @@ -147,7 +153,7 @@ typedef struct ctf_dtdef ctf_list_t dtd_list; /* List forward/back pointers. */ char *dtd_name; /* Name associated with definition (if any). */ ctf_id_t dtd_type; /* Type identifier for this definition. */ - ctf_type_t dtd_data; /* Type node (see <ctf.h>). */ + ctf_type_t dtd_data; /* Type node: name left unpopulated. */ union { ctf_list_t dtu_members; /* struct, union, or enum */ @@ -173,6 +179,30 @@ typedef struct ctf_bundle ctf_dtdef_t *ctb_dtd; /* CTF dynamic type definition (if any). */ } ctf_bundle_t; +/* Atoms associate strings with a list of the CTF items that reference that + string, so that ctf_update() can instantiate all the strings using the + ctf_str_atoms and then reassociate them with the real string later. + + Strings can be interned into ctf_str_atom without having refs associated + with them, for values that are returned to callers, etc. Items are only + removed from this table on ctf_close(), but on every ctf_update(), all the + csa_refs in all entries are purged. */ + +typedef struct ctf_str_atom +{ + const char *csa_str; /* Backpointer to string (hash key). */ + ctf_list_t csa_refs; /* This string's refs. */ + unsigned long csa_snapshot_id; /* Snapshot ID at time of creation. */ +} ctf_str_atom_t; + +/* The refs of a single string in the atoms table. */ + +typedef struct ctf_str_atom_ref +{ + ctf_list_t caf_list; /* List forward/back pointers. */ + uint32_t *caf_ref; /* A single ref to this string. */ +} ctf_str_atom_ref_t; + /* The ctf_file is the structure used to represent a CTF container to library clients, who see it only as an opaque pointer. Modifications can therefore be made freely to this structure without regard to client versioning. The @@ -198,6 +228,8 @@ struct ctf_file ctf_hash_t *ctf_names; /* Hash table of remaining type names. */ ctf_lookup_t ctf_lookups[5]; /* Pointers to hashes for name lookup. */ ctf_strs_t ctf_str[2]; /* Array of string table base and bounds. */ + ctf_dynhash_t *ctf_str_atoms; /* Hash table of ctf_str_atoms_t. */ + uint64_t ctf_str_num_refs; /* Number of refs to cts_str_atoms. */ const unsigned char *ctf_base; /* Base of CTF header + uncompressed buffer. */ const unsigned char *ctf_buf; /* Uncompressed CTF data buffer. */ size_t ctf_size; /* Size of CTF header + uncompressed data. */ @@ -223,7 +255,6 @@ struct ctf_file ctf_list_t ctf_dtdefs; /* List of dynamic type definitions. */ ctf_dynhash_t *ctf_dvhash; /* Hash of dynamic variable mappings. */ ctf_list_t ctf_dvdefs; /* List of dynamic variable definitions. */ - size_t ctf_dtvstrlen; /* Total length of dynamic type+var strings. */ unsigned long ctf_dtnextid; /* Next dynamic type id to assign. */ unsigned long ctf_dtoldid; /* Oldest id that has been committed. */ unsigned long ctf_snapshots; /* ctf_snapshot() plus ctf_update() count. */ @@ -341,6 +372,13 @@ extern char *ctf_decl_buf (ctf_decl_t *cd); extern const char *ctf_strraw (ctf_file_t *, uint32_t); extern const char *ctf_strptr (ctf_file_t *, uint32_t); +extern int ctf_str_create_atoms (ctf_file_t *); +extern void ctf_str_free_atoms (ctf_file_t *); +extern const char *ctf_str_add (ctf_file_t *, const char *); +extern const char *ctf_str_add_ref (ctf_file_t *, const char *, uint32_t *); +extern void ctf_str_rollback (ctf_file_t *, ctf_snapshot_id_t); +extern void ctf_str_purge_refs (ctf_file_t *); +extern ctf_strs_writable_t ctf_str_write_strtab (ctf_file_t *); extern struct ctf_archive *ctf_arc_open_internal (const char *, int *); extern struct ctf_archive *ctf_arc_bufopen (const void *, size_t, int *); @@ -356,6 +394,7 @@ extern ssize_t ctf_pread (int fd, void *buf, ssize_t count, off_t offset); _libctf_malloc_ extern void *ctf_alloc (size_t); extern void ctf_free (void *); +extern void *ctf_realloc (ctf_file_t *, void *, size_t); _libctf_malloc_ extern char *ctf_strdup (const char *); |