From: Jakub Jelinek <jakub@redhat.com>
To: djamel anonymous <djam8193ah@hotmail.com>
Cc: binutils@sources.redhat.com, drepper@redhat.com,
michael.meeks@novell.com, libc-alpha@sources.redhat.com
Subject: Re: DT_GNU_HASH latest patches
Date: Fri, 07 Jul 2006 14:45:00 -0000 [thread overview]
Message-ID: <20060707144406.GO3823@sunsite.mff.cuni.cz> (raw)
In-Reply-To: <BAY22-F8ACC5B9D3CE16C97BA51FC7770@phx.gbl>
[-- Attachment #1: Type: text/plain, Size: 915 bytes --]
On Thu, Jul 06, 2006 at 07:53:29PM +0000, djamel anonymous wrote:
> Hello, i am writing you this time about the first variant.after looking at
> the benchmark results i noted that there have been a reduction in the
> number of l1 cache misses; a reduction in l1 cache misses means a win of 12
> cycles ; the difference between the latency of l2 cache and that of l1
> cache 15-3.on the other hand replacing a division by a binary and & is a
> win of at least 25 cycles, so it think that avoiding tthe division in the
> common case may improve performance.
I don't think it is the modulo that matters, but the smaller footprint
of .gnu.hash case in that case. I have implemented what I think you meant
and the numbers actually convinced me.
So here is the new set of patches and new statistics.
take1 is 2006-06-28 state of things, take2 2006-07-03, take3 2006-07-05
and take4 what is attached here.
Jakub
[-- Attachment #2: binutils-hash-style.patch --]
[-- Type: text/plain, Size: 39189 bytes --]
2006-07-07 Jakub Jelinek <jakub@redhat.com>
include/
* bfdlink.h (struct bfd_link_info): Add emit_hash and
emit_gnu_hash bitfields.
include/elf/
* common.h (SHT_GNU_HASH, DT_GNU_HASH): Define.
ld/
* scripttempl/elf.sc: Add .gnu.hash section.
* emultempl/elf32.em (OPTION_HASH_STYLE): Define.
(gld${EMULATION_NAME}_add_options): Register --hash-style option.
(gld${EMULATION_NAME}_handle_option): Handle it.
(gld${EMULATION_NAME}_list_options): Document it.
* ldmain.c (main): Initialize emit_hash and emit_gnu_hash.
* ld.texinfo: Document --hash-style option.
bfd/
* elf.c (_bfd_elf_print_private_bfd_data): Handle DT_GNU_HASH.
(bfd_section_from_shdr, elf_fake_sections, assign_section_numbers):
Handle SHT_GNU_HASH.
(special_sections_g): Include .gnu.hash section.
(bfd_elf_gnu_hash): New function.
* elf-bfd.h (bfd_elf_gnu_hash, _bfd_elf_hash_symbol): New prototypes.
(struct elf_backend_data): Add elf_hash_symbol method.
* elflink.c (_bfd_elf_link_create_dynamic_sections): Create .hash
only if info->emit_hash, create .gnu.hash section if
info->emit_gnu_hash.
(struct collect_gnu_hash_codes): New type.
(elf_collect_gnu_hash_codes, elf_renumber_gnu_hash_syms,
_bfd_elf_hash_symbol): New functions.
(compute_bucket_count): Don't compute HASHCODES array, instead add
that and NSYMS as arguments. Use bed->s->sizeof_hash_entry
instead of bed->s->arch_size / 8. Fix .hash size estimation.
When not optimizing, use the number of hashed symbols rather than
dynsymcount.
(bfd_elf_size_dynamic_sections): Only add DT_HASH if info->emit_hash,
and ADD DT_GNU_HASH if info->emit_gnu_hash.
(bfd_elf_size_dynsym_hash_dynstr): Size .hash only if info->emit_hash,
adjust compute_bucket_count caller. Create and populate .gnu.hash
section if info->emit_gnu_hash.
(elf_link_output_extsym): Only populate .hash section if
finfo->hash_sec != NULL.
(bfd_elf_final_link): Adjust assertion. Handle DT_GNU_HASH.
* elfxx-target.h (elf_backend_hash_symbol): Define if not yet defined.
(elfNN_bed): Add elf_backend_hash_symbol.
* elf64-x86-64.c (elf64_x86_64_hash_symbol): New function.
(elf_backend_hash_symbol): Define.
* elf32-i386.c (elf_i386_hash_symbol): New function.
(elf_backend_hash_symbol): Define.
binutils/
* readelf.c (get_dynamic_type): Handle DT_GNU_HASH.
(get_section_type_name): Handle SHT_GNU_HASH.
(dynamic_info_DT_GNU_HASH): New variable.
(process_dynamic_section): Handle DT_GNU_HASH.
(process_symbol_table): Print also DT_GNU_HASH histogram.
--- ld/scripttempl/elf.sc.jj 2006-01-01 01:02:16.000000000 +0100
+++ ld/scripttempl/elf.sc 2006-06-22 11:11:53.000000000 +0200
@@ -260,6 +260,7 @@ SECTIONS
${INITIAL_READONLY_SECTIONS}
${TEXT_DYNAMIC+${DYNAMIC}}
.hash ${RELOCATING-0} : { *(.hash) }
+ .gnu.hash ${RELOCATING-0} : { *(.gnu.hash) }
.dynsym ${RELOCATING-0} : { *(.dynsym) }
.dynstr ${RELOCATING-0} : { *(.dynstr) }
.gnu.version ${RELOCATING-0} : { *(.gnu.version) }
--- ld/ldmain.c.jj 2006-06-01 15:50:33.000000000 +0200
+++ ld/ldmain.c 2006-06-22 11:21:11.000000000 +0200
@@ -304,6 +304,8 @@ main (int argc, char **argv)
link_info.create_object_symbols_section = NULL;
link_info.gc_sym_list = NULL;
link_info.base_file = NULL;
+ link_info.emit_hash = TRUE;
+ link_info.emit_gnu_hash = FALSE;
/* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init
and _fini symbols. We are compatible. */
link_info.init_function = "_init";
--- ld/ld.texinfo.jj 2006-06-15 14:31:06.000000000 +0200
+++ ld/ld.texinfo 2006-06-22 14:03:21.000000000 +0200
@@ -1883,6 +1883,14 @@ time it takes the linker to perform its
increasing the linker's memory requirements. Similarly reducing this
value can reduce the memory requirements at the expense of speed.
+@kindex --hash-style=@var{style}
+@item --hash-style=@var{style}
+Set the type of linker's hash table(s). @var{style} can be either
+@code{sysv} for classic ELF @code{.hash} section, @code{gnu} for
+new style GNU @code{.gnu.hash} section or @code{both} for both
+the classic ELF @code{.hash} and new style GNU @code{.gnu.hash}
+hash tables. The default is @code{sysv}.
+
@kindex --reduce-memory-overheads
@item --reduce-memory-overheads
This option reduces memory requirements at ld runtime, at the expense of
--- ld/emultempl/elf32.em.jj 2006-06-20 18:34:24.000000000 +0200
+++ ld/emultempl/elf32.em 2006-06-22 14:39:25.000000000 +0200
@@ -1719,6 +1719,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1)
#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1)
+#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1)
static void
gld${EMULATION_NAME}_add_options
@@ -1735,6 +1736,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
{"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
{"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
{"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS},
+ {"hash-style", required_argument, NULL, OPTION_HASH_STYLE},
{"Bgroup", no_argument, NULL, OPTION_GROUP},
EOF
fi
@@ -1791,6 +1793,22 @@ cat >>e${EMULATION_NAME}.c <<EOF
add_excluded_libs (optarg);
break;
+ case OPTION_HASH_STYLE:
+ link_info.emit_hash = FALSE;
+ link_info.emit_gnu_hash = FALSE;
+ if (strcmp (optarg, "sysv") == 0)
+ link_info.emit_hash = TRUE;
+ else if (strcmp (optarg, "gnu") == 0)
+ link_info.emit_gnu_hash = TRUE;
+ else if (strcmp (optarg, "both") == 0)
+ {
+ link_info.emit_hash = TRUE;
+ link_info.emit_gnu_hash = TRUE;
+ }
+ else
+ einfo (_("%P%F: invalid hash style \`%s'\n"), optarg);
+ break;
+
case 'z':
if (strcmp (optarg, "initfirst") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
@@ -1894,6 +1912,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n"));
fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n"));
fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
+ fprintf (file, _(" --hash-stylle=STYLE\tSet hash style to sysv, gnu or both\n"));
fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
fprintf (file, _(" -z defs\t\tReport unresolved symbols in object files.\n"));
fprintf (file, _(" -z execstack\t\tMark executable as requiring executable stack\n"));
--- bfd/elf-bfd.h.jj 2006-06-20 18:34:24.000000000 +0200
+++ bfd/elf-bfd.h 2006-07-06 15:48:12.000000000 +0200
@@ -1038,6 +1038,9 @@ struct elf_backend_data
bfd_boolean *, bfd_boolean *,
bfd *, asection **);
+ /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+ bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *);
+
/* Used to handle bad SHF_LINK_ORDER input. */
bfd_error_handler_type link_order_error_handler;
@@ -1481,6 +1484,8 @@ extern bfd_vma _bfd_elf_section_offset
extern unsigned long bfd_elf_hash
(const char *);
+extern unsigned long bfd_elf_gnu_hash
+ (const char *);
extern bfd_reloc_status_type bfd_elf_generic_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
@@ -1651,6 +1656,8 @@ extern bfd_boolean _bfd_elf_merge_symbol
struct elf_link_hash_entry **, bfd_boolean *,
bfd_boolean *, bfd_boolean *, bfd_boolean *);
+extern bfd_boolean _bfd_elf_hash_symbol (struct elf_link_hash_entry *);
+
extern bfd_boolean _bfd_elf_add_default_symbol
(bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
--- bfd/elf64-x86-64.c.jj 2006-06-20 11:57:19.000000000 +0200
+++ bfd/elf64-x86-64.c 2006-07-06 16:54:21.000000000 +0200
@@ -3615,6 +3615,19 @@ elf64_x86_64_additional_program_headers
return count;
}
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+
+static bfd_boolean
+elf64_x86_64_hash_symbol (struct elf_link_hash_entry *h)
+{
+ if (h->plt.offset != (bfd_vma) -1
+ && !h->def_regular
+ && !h->pointer_equality_needed)
+ return FALSE;
+
+ return _bfd_elf_hash_symbol (h);
+}
+
static const struct bfd_elf_special_section
elf64_x86_64_special_sections[]=
{
@@ -3688,5 +3701,7 @@ static const struct bfd_elf_special_sect
elf64_x86_64_special_sections
#define elf_backend_additional_program_headers \
elf64_x86_64_additional_program_headers
+#define elf_backend_hash_symbol \
+ elf64_x86_64_hash_symbol
#include "elf64-target.h"
--- bfd/elf.c.jj 2006-06-20 18:34:24.000000000 +0200
+++ bfd/elf.c 2006-06-26 16:17:28.000000000 +0200
@@ -206,6 +206,21 @@ bfd_elf_hash (const char *namearg)
return h & 0xffffffff;
}
+/* DT_GNU_HASH hash function. Do not change this function; you will
+ cause invalid hash tables to be generated. */
+
+unsigned long
+bfd_elf_gnu_hash (const char *namearg)
+{
+ const unsigned char *name = (const unsigned char *) namearg;
+ unsigned long h = 5381;
+ unsigned char ch;
+
+ while ((ch = *name++) != '\0')
+ h = (h << 5) + h + ch;
+ return h & 0xffffffff;
+}
+
bfd_boolean
bfd_elf_mkobject (bfd *abfd)
{
@@ -1239,6 +1254,7 @@ _bfd_elf_print_private_bfd_data (bfd *ab
case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break;
case DT_USED: name = "USED"; break;
case DT_FILTER: name = "FILTER"; stringp = TRUE; break;
+ case DT_GNU_HASH: name = "GNU_HASH"; break;
}
fprintf (f, " %-11s ", name);
@@ -1823,6 +1839,7 @@ bfd_section_from_shdr (bfd *abfd, unsign
case SHT_FINI_ARRAY: /* .fini_array section. */
case SHT_PREINIT_ARRAY: /* .preinit_array section. */
case SHT_GNU_LIBLIST: /* .gnu.liblist section. */
+ case SHT_GNU_HASH: /* .gnu.hash section. */
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
case SHT_DYNAMIC: /* Dynamic linking information. */
@@ -2295,6 +2312,7 @@ static const struct bfd_elf_special_sect
{ ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 },
{ ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC },
{ ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC },
+ { ".gnu.hash", 9, 0, SHT_GNU_HASH, SHF_ALLOC },
{ NULL, 0, 0, 0, 0 }
};
@@ -2811,6 +2829,10 @@ elf_fake_sections (bfd *abfd, asection *
case SHT_GROUP:
this_hdr->sh_entsize = 4;
break;
+
+ case SHT_GNU_HASH:
+ this_hdr->sh_entsize = 4;
+ break;
}
if ((asect->flags & SEC_ALLOC) != 0)
@@ -3256,6 +3278,7 @@ assign_section_numbers (bfd *abfd, struc
break;
case SHT_HASH:
+ case SHT_GNU_HASH:
case SHT_GNU_versym:
/* sh_link is the section header index of the symbol table
this hash table or version table is for. */
--- bfd/elf32-i386.c.jj 2006-06-23 15:32:34.000000000 +0200
+++ bfd/elf32-i386.c 2006-07-06 16:56:24.000000000 +0200
@@ -3835,6 +3835,18 @@ elf_i386_plt_sym_val (bfd_vma i, const a
return plt->vma + (i + 1) * PLT_ENTRY_SIZE;
}
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+
+static bfd_boolean
+elf_i386_hash_symbol (struct elf_link_hash_entry *h)
+{
+ if (h->plt.offset != (bfd_vma) -1
+ && !h->def_regular
+ && !h->pointer_equality_needed)
+ return FALSE;
+
+ return _bfd_elf_hash_symbol (h);
+}
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
#define TARGET_LITTLE_NAME "elf32-i386"
@@ -3875,6 +3887,7 @@ elf_i386_plt_sym_val (bfd_vma i, const a
#define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections
#define elf_backend_always_size_sections elf_i386_always_size_sections
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
+#define elf_backend_hash_symbol elf_i386_hash_symbol
#include "elf32-target.h"
--- bfd/elflink.c.jj 2006-06-20 18:34:53.000000000 +0200
+++ bfd/elflink.c 2006-07-07 16:19:55.000000000 +0200
@@ -240,12 +240,24 @@ _bfd_elf_link_create_dynamic_sections (b
if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".hash",
- flags | SEC_READONLY);
- if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
- return FALSE;
- elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
+ if (info->emit_hash)
+ {
+ s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ return FALSE;
+ elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
+ }
+
+ if (info->emit_gnu_hash)
+ {
+ s = bfd_make_section_with_flags (abfd, ".gnu.hash",
+ flags | SEC_READONLY);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, 3))
+ return FALSE;
+ elf_section_data (s)->this_hdr.sh_entsize = 4;
+ }
/* Let the backend create the rest of the sections. This lets the
backend set the right flags. The backend will normally create
@@ -4811,6 +4823,126 @@ elf_collect_hash_codes (struct elf_link_
return TRUE;
}
+struct collect_gnu_hash_codes
+{
+ bfd *output_bfd;
+ const struct elf_backend_data *bed;
+ unsigned long int nsyms;
+ unsigned long int maskbits;
+ unsigned long int *hashcodes;
+ unsigned long int *hashval;
+ unsigned long int *indx;
+ unsigned long int *counts;
+ unsigned long int *bitmask;
+ bfd_byte *contents;
+ long int min_dynindx;
+ unsigned long int bucketcount;
+ unsigned long int symindx;
+ long int local_indx;
+};
+
+/* This function will be called though elf_link_hash_traverse to store
+ all hash value of the exported symbols in an array. */
+
+static bfd_boolean
+elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
+{
+ struct collect_gnu_hash_codes *s = data;
+ const char *name;
+ char *p;
+ unsigned long ha;
+ char *alc = NULL;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ /* Ignore indirect symbols. These are added by the versioning code. */
+ if (h->dynindx == -1)
+ return TRUE;
+
+ /* Ignore also local symbols and undefined symbols. */
+ if (! (*s->bed->elf_hash_symbol) (h))
+ return TRUE;
+
+ name = h->root.root.string;
+ p = strchr (name, ELF_VER_CHR);
+ if (p != NULL)
+ {
+ alc = bfd_malloc (p - name + 1);
+ memcpy (alc, name, p - name);
+ alc[p - name] = '\0';
+ name = alc;
+ }
+
+ /* Compute the hash value. */
+ ha = bfd_elf_gnu_hash (name);
+
+ /* Store the found hash value in the array for compute_bucket_count,
+ and also for .dynsym reordering purposes. */
+ s->hashcodes[s->nsyms] = ha;
+ s->hashval[h->dynindx] = ha;
+ ++s->nsyms;
+ if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx)
+ s->min_dynindx = h->dynindx;
+
+ if (alc != NULL)
+ free (alc);
+
+ return TRUE;
+}
+
+/* This function will be called though elf_link_hash_traverse to do
+ final dynaminc symbol renumbering. */
+
+static bfd_boolean
+elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
+{
+ struct collect_gnu_hash_codes *s = data;
+ unsigned long int bucket;
+ unsigned long int val;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ /* Ignore indirect symbols. */
+ if (h->dynindx == -1)
+ return TRUE;
+
+ /* Ignore also local symbols and undefined symbols. */
+ if (! (*s->bed->elf_hash_symbol) (h))
+ {
+ if (h->dynindx >= s->min_dynindx)
+ h->dynindx = s->local_indx++;
+ return TRUE;
+ }
+
+ bucket = s->hashval[h->dynindx] % s->bucketcount;
+ val = (s->hashval[h->dynindx] >> 5) & ((s->maskbits >> 5) - 1);
+ s->bitmask[val] |= ((unsigned long int) 1) << (s->hashval[h->dynindx] & 31);
+ val = s->hashval[h->dynindx] & ~(unsigned long int) 1;
+ if (s->counts[bucket] == 1)
+ /* Last element terminates the chain. */
+ val |= 1;
+ bfd_put_32 (s->output_bfd, val,
+ s->contents + (s->indx[bucket] - s->symindx) * 4);
+ --s->counts[bucket];
+ h->dynindx = s->indx[bucket]++;
+ return TRUE;
+}
+
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+
+bfd_boolean
+_bfd_elf_hash_symbol (struct elf_link_hash_entry *h)
+{
+ return !(h->forced_local
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak
+ || ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section == NULL));
+}
+
/* Array used to determine the number of hash table buckets to use
based on the number of symbols there are. If there are fewer than
3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets,
@@ -4832,42 +4964,26 @@ static const size_t elf_buckets[] =
Therefore the result is always a good payoff between few collisions
(= short chain lengths) and table size. */
static size_t
-compute_bucket_count (struct bfd_link_info *info)
+compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes,
+ unsigned long int nsyms, int gnu_hash)
{
size_t dynsymcount = elf_hash_table (info)->dynsymcount;
size_t best_size = 0;
- unsigned long int *hashcodes;
- unsigned long int *hashcodesp;
unsigned long int i;
bfd_size_type amt;
- /* Compute the hash values for all exported symbols. At the same
- time store the values in an array so that we could use them for
- optimizations. */
- amt = dynsymcount;
- amt *= sizeof (unsigned long int);
- hashcodes = bfd_malloc (amt);
- if (hashcodes == NULL)
- return 0;
- hashcodesp = hashcodes;
-
- /* Put all hash values in HASHCODES. */
- elf_link_hash_traverse (elf_hash_table (info),
- elf_collect_hash_codes, &hashcodesp);
-
/* We have a problem here. The following code to optimize the table
size requires an integer type with more the 32 bits. If
BFD_HOST_U_64_BIT is set we know about such a type. */
#ifdef BFD_HOST_U_64_BIT
if (info->optimize)
{
- unsigned long int nsyms = hashcodesp - hashcodes;
size_t minsize;
size_t maxsize;
BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
- unsigned long int *counts ;
bfd *dynobj = elf_hash_table (info)->dynobj;
const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+ unsigned long int *counts;
/* Possible optimization parameters: if we have NSYMS symbols we say
that the hashing table must at least have NSYMS/4 and at most
@@ -4876,6 +4992,13 @@ compute_bucket_count (struct bfd_link_in
if (minsize == 0)
minsize = 1;
best_size = maxsize = nsyms * 2;
+ if (gnu_hash)
+ {
+ if (minsize < 2)
+ minsize = 2;
+ if ((best_size & 31) == 0)
+ ++best_size;
+ }
/* Create array where we count the collisions in. We must use bfd_malloc
since the size could be large. */
@@ -4883,10 +5006,7 @@ compute_bucket_count (struct bfd_link_in
amt *= sizeof (unsigned long int);
counts = bfd_malloc (amt);
if (counts == NULL)
- {
- free (hashcodes);
- return 0;
- }
+ return 0;
/* Compute the "optimal" size for the hash table. The criteria is a
minimal chain length. The minor criteria is (of course) the size
@@ -4898,6 +5018,9 @@ compute_bucket_count (struct bfd_link_in
unsigned long int j;
unsigned long int fact;
+ if (gnu_hash && (i & 31) == 0)
+ continue;
+
memset (counts, '\0', i * sizeof (unsigned long int));
/* Determine how often each hash bucket is used. */
@@ -4913,9 +5036,9 @@ compute_bucket_count (struct bfd_link_in
# define BFD_TARGET_PAGESIZE (4096)
# endif
- /* We in any case need 2 + NSYMS entries for the size values and
- the chains. */
- max = (2 + nsyms) * (bed->s->arch_size / 8);
+ /* We in any case need 2 + DYNSYMCOUNT entries for the size values
+ and the chains. */
+ max = (2 + dynsymcount) * bed->s->sizeof_hash_entry;
# if 1
/* Variant 1: optimize for short chains. We add the squares
@@ -4925,7 +5048,7 @@ compute_bucket_count (struct bfd_link_in
max += counts[j] * counts[j];
/* This adds penalties for the overall size of the table. */
- fact = i / (BFD_TARGET_PAGESIZE / (bed->s->arch_size / 8)) + 1;
+ fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1;
max *= fact * fact;
# else
/* Variant 2: Optimize a lot more for small table. Here we
@@ -4936,7 +5059,7 @@ compute_bucket_count (struct bfd_link_in
/* The overall size of the table is considered, but not as
strong as in variant 1, where it is squared. */
- fact = i / (BFD_TARGET_PAGESIZE / (bed->s->arch_size / 8)) + 1;
+ fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1;
max *= fact;
# endif
@@ -4959,14 +5082,13 @@ compute_bucket_count (struct bfd_link_in
for (i = 0; elf_buckets[i] != 0; i++)
{
best_size = elf_buckets[i];
- if (dynsymcount < elf_buckets[i + 1])
+ if (nsyms < elf_buckets[i + 1])
break;
}
+ if (gnu_hash && best_size < 2)
+ best_size = 2;
}
- /* Free the arrays we needed. */
- free (hashcodes);
-
return best_size;
}
@@ -5324,7 +5446,10 @@ bfd_elf_size_dynamic_sections (bfd *outp
bfd_size_type strsize;
strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
- if (!_bfd_elf_add_dynamic_entry (info, DT_HASH, 0)
+ if ((info->emit_hash
+ && !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0))
+ || (info->emit_gnu_hash
+ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0))
|| !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
@@ -5726,8 +5851,6 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *ou
asection *s;
bfd_size_type dynsymcount;
unsigned long section_sym_count;
- size_t bucketcount = 0;
- size_t hash_entry_size;
unsigned int dtagcount;
dynobj = elf_hash_table (info)->dynobj;
@@ -5778,23 +5901,195 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *ou
memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym);
}
+ elf_hash_table (info)->bucketcount = 0;
+
/* Compute the size of the hashing table. As a side effect this
computes the hash values for all the names we export. */
- bucketcount = compute_bucket_count (info);
+ if (info->emit_hash)
+ {
+ unsigned long int *hashcodes;
+ unsigned long int *hashcodesp;
+ bfd_size_type amt;
+ unsigned long int nsyms;
+ size_t bucketcount;
+ size_t hash_entry_size;
+
+ /* Compute the hash values for all exported symbols. At the same
+ time store the values in an array so that we could use them for
+ optimizations. */
+ amt = dynsymcount * sizeof (unsigned long int);
+ hashcodes = bfd_malloc (amt);
+ if (hashcodes == NULL)
+ return FALSE;
+ hashcodesp = hashcodes;
- s = bfd_get_section_by_name (dynobj, ".hash");
- BFD_ASSERT (s != NULL);
- hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
- s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
- s->contents = bfd_zalloc (output_bfd, s->size);
- if (s->contents == NULL)
- return FALSE;
+ /* Put all hash values in HASHCODES. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_collect_hash_codes, &hashcodesp);
+
+ nsyms = hashcodesp - hashcodes;
+ bucketcount
+ = compute_bucket_count (info, hashcodes, nsyms, 0);
+ free (hashcodes);
+
+ if (bucketcount == 0)
+ return FALSE;
- bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
- bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
- s->contents + hash_entry_size);
+ elf_hash_table (info)->bucketcount = bucketcount;
- elf_hash_table (info)->bucketcount = bucketcount;
+ s = bfd_get_section_by_name (dynobj, ".hash");
+ BFD_ASSERT (s != NULL);
+ hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
+ s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
+ s->contents = bfd_zalloc (output_bfd, s->size);
+ if (s->contents == NULL)
+ return FALSE;
+
+ bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
+ bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
+ s->contents + hash_entry_size);
+ }
+
+ if (info->emit_gnu_hash)
+ {
+ size_t i, cnt;
+ unsigned char *contents;
+ struct collect_gnu_hash_codes cinfo;
+ bfd_size_type amt;
+ size_t bucketcount;
+
+ memset (&cinfo, 0, sizeof (cinfo));
+
+ /* Compute the hash values for all exported symbols. At the same
+ time store the values in an array so that we could use them for
+ optimizations. */
+ amt = dynsymcount * 2 * sizeof (unsigned long int);
+ cinfo.hashcodes = bfd_malloc (amt);
+ if (cinfo.hashcodes == NULL)
+ return FALSE;
+
+ cinfo.hashval = cinfo.hashcodes + dynsymcount;
+ cinfo.min_dynindx = -1;
+ cinfo.output_bfd = output_bfd;
+ cinfo.bed = bed;
+
+ /* Put all hash values in HASHCODES. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_collect_gnu_hash_codes, &cinfo);
+
+ bucketcount
+ = compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1);
+
+ if (bucketcount == 0)
+ {
+ free (cinfo.hashcodes);
+ return FALSE;
+ }
+
+ s = bfd_get_section_by_name (dynobj, ".gnu.hash");
+ BFD_ASSERT (s != NULL);
+
+ if (cinfo.nsyms == 0)
+ {
+ /* Empty .gnu.hash section is special. */
+ BFD_ASSERT (cinfo.min_dynindx == -1);
+ free (cinfo.hashcodes);
+ s->size = 5 * 4;
+ contents = bfd_zalloc (output_bfd, s->size);
+ if (contents == NULL)
+ return FALSE;
+ s->contents = contents;
+ /* 1 empty bucket. */
+ bfd_put_32 (output_bfd, 1, contents);
+ /* SYMIDX above the special symbol 0. */
+ bfd_put_32 (output_bfd, 1, contents + 4);
+ /* Just one word for bitmask. */
+ bfd_put_32 (output_bfd, 1, contents + 8);
+ /* No hashes are valid - empty bitmask. */
+ bfd_put_32 (output_bfd, 0, contents + 12);
+ /* No hashes in the only bucket. */
+ bfd_put_32 (output_bfd, 0, contents + 16);
+ }
+ else
+ {
+ BFD_ASSERT (cinfo.min_dynindx != -1);
+
+ cinfo.maskbits = bfd_log2 (cinfo.nsyms) + 1;
+ if (cinfo.maskbits < 3)
+ cinfo.maskbits = 1 << 5;
+ else if ((1 << (cinfo.maskbits - 2)) & cinfo.nsyms)
+ cinfo.maskbits = 1 << (cinfo.maskbits + 3);
+ else
+ cinfo.maskbits = 1 << (cinfo.maskbits + 2);
+ amt = bucketcount * sizeof (unsigned long int) * 2;
+ amt += (cinfo.maskbits / 32) * sizeof (unsigned long int);
+ cinfo.counts = bfd_malloc (amt);
+ if (cinfo.counts == NULL)
+ {
+ free (cinfo.hashcodes);
+ return FALSE;
+ }
+
+ /* Determine how often each hash bucket is used. */
+ memset (cinfo.counts, 0,
+ bucketcount * sizeof (cinfo.counts[0]));
+ for (i = 0; i < cinfo.nsyms; ++i)
+ ++cinfo.counts[cinfo.hashcodes[i] % bucketcount];
+
+ cinfo.indx = cinfo.counts + bucketcount;
+ cinfo.bitmask = cinfo.counts + 2 * bucketcount;
+ memset (cinfo.bitmask, 0, (cinfo.maskbits / 32)
+ * sizeof (unsigned long int));
+ cinfo.symindx = dynsymcount - cinfo.nsyms;
+ for (i = 0, cnt = cinfo.symindx; i < bucketcount; ++i)
+ if (cinfo.counts[i] != 0)
+ {
+ cinfo.indx[i] = cnt;
+ cnt += cinfo.counts[i];
+ }
+ BFD_ASSERT (cnt == dynsymcount);
+ cinfo.bucketcount = bucketcount;
+ cinfo.local_indx = cinfo.min_dynindx;
+
+ s->size = (3 + bucketcount + cinfo.nsyms) * 4;
+ s->size += cinfo.maskbits / 8;
+ contents = bfd_zalloc (output_bfd, s->size);
+ if (contents == NULL)
+ {
+ free (cinfo.counts);
+ free (cinfo.hashcodes);
+ return FALSE;
+ }
+
+ s->contents = contents;
+ bfd_put_32 (output_bfd, bucketcount, contents);
+ bfd_put_32 (output_bfd, cinfo.symindx, contents + 4);
+ bfd_put_32 (output_bfd, cinfo.maskbits / 32, contents + 8);
+ contents += 12 + cinfo.maskbits / 8;
+
+ for (i = 0; i < bucketcount; ++i)
+ {
+ if (cinfo.counts[i] == 0)
+ bfd_put_32 (output_bfd, 0, contents);
+ else
+ bfd_put_32 (output_bfd, cinfo.indx[i], contents);
+ contents += 4;
+ }
+
+ cinfo.contents = contents;
+
+ /* Renumber dynamic symbols, populate .gnu.hash section. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_renumber_gnu_hash_syms, &cinfo);
+
+ contents = s->contents + 12;
+ for (i = 0; i < cinfo.maskbits / 32; ++i, contents += 4)
+ bfd_put_32 (output_bfd, cinfo.bitmask[i], contents);
+
+ free (cinfo.counts);
+ free (cinfo.hashcodes);
+ }
+ }
s = bfd_get_section_by_name (dynobj, ".dynstr");
BFD_ASSERT (s != NULL);
@@ -6663,9 +6958,6 @@ elf_link_output_extsym (struct elf_link_
{
size_t bucketcount;
size_t bucket;
- size_t hash_entry_size;
- bfd_byte *bucketpos;
- bfd_vma chain;
bfd_byte *esym;
sym.st_name = h->dynstr_index;
@@ -6679,15 +6971,23 @@ elf_link_output_extsym (struct elf_link_
bucketcount = elf_hash_table (finfo->info)->bucketcount;
bucket = h->u.elf_hash_value % bucketcount;
- hash_entry_size
- = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
- bucketpos = ((bfd_byte *) finfo->hash_sec->contents
- + (bucket + 2) * hash_entry_size);
- chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
- bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
- bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
- ((bfd_byte *) finfo->hash_sec->contents
- + (bucketcount + 2 + h->dynindx) * hash_entry_size));
+
+ if (finfo->hash_sec != NULL)
+ {
+ size_t hash_entry_size;
+ bfd_byte *bucketpos;
+ bfd_vma chain;
+
+ hash_entry_size
+ = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
+ bucketpos = ((bfd_byte *) finfo->hash_sec->contents
+ + (bucket + 2) * hash_entry_size);
+ chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
+ bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
+ bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
+ ((bfd_byte *) finfo->hash_sec->contents
+ + (bucketcount + 2 + h->dynindx) * hash_entry_size));
+ }
if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
{
@@ -7861,7 +8161,7 @@ bfd_elf_final_link (bfd *abfd, struct bf
{
finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
- BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL);
+ BFD_ASSERT (finfo.dynsym_sec != NULL);
finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
/* Note that it is OK if symver_sec is NULL. */
}
@@ -8621,6 +8921,9 @@ bfd_elf_final_link (bfd *abfd, struct bf
case DT_HASH:
name = ".hash";
goto get_vma;
+ case DT_GNU_HASH:
+ name = ".gnu.hash";
+ goto get_vma;
case DT_STRTAB:
name = ".dynstr";
goto get_vma;
--- bfd/elfxx-target.h.jj 2006-06-20 18:34:24.000000000 +0200
+++ bfd/elfxx-target.h 2006-07-06 15:38:39.000000000 +0200
@@ -563,6 +563,10 @@
#define elf_backend_merge_symbol NULL
#endif
+#ifndef elf_backend_hash_symbol
+#define elf_backend_hash_symbol _bfd_elf_hash_symbol
+#endif
+
extern const struct elf_size_info _bfd_elfNN_size_info;
#ifndef INCLUDED_TARGET_FILE
@@ -643,6 +647,7 @@ static struct elf_backend_data elfNN_bed
elf_backend_common_section_index,
elf_backend_common_section,
elf_backend_merge_symbol,
+ elf_backend_hash_symbol,
elf_backend_link_order_error_handler,
elf_backend_relplt_name,
ELF_MACHINE_ALT1,
--- include/elf/common.h.jj 2006-02-17 15:36:26.000000000 +0100
+++ include/elf/common.h 2006-06-22 10:43:21.000000000 +0200
@@ -338,6 +338,7 @@
#define SHT_LOOS 0x60000000 /* First of OS specific semantics */
#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */
+#define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table */
#define SHT_GNU_LIBLIST 0x6ffffff7 /* List of prelink dependencies */
/* The next three section types are defined by Solaris, and are named
@@ -577,6 +578,7 @@
#define DT_VALRNGHI 0x6ffffdff
#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_HASH 0x6ffffef5
#define DT_TLSDESC_PLT 0x6ffffef6
#define DT_TLSDESC_GOT 0x6ffffef7
#define DT_GNU_CONFLICT 0x6ffffef8
--- include/bfdlink.h.jj 2006-04-07 17:17:29.000000000 +0200
+++ include/bfdlink.h 2006-06-22 11:11:20.000000000 +0200
@@ -324,6 +324,12 @@ struct bfd_link_info
/* TRUE if unreferenced sections should be removed. */
unsigned int gc_sections: 1;
+ /* TRUE if .hash section should be created. */
+ unsigned int emit_hash: 1;
+
+ /* TRUE if .gnu.hash section should be created. */
+ unsigned int emit_gnu_hash: 1;
+
/* What to do with unresolved symbols in an object file.
When producing executables the default is GENERATE_ERROR.
When producing shared libraries the default is IGNORE. The
--- binutils/readelf.c.jj 2006-05-30 16:13:54.000000000 +0200
+++ binutils/readelf.c 2006-07-07 16:29:42.000000000 +0200
@@ -135,6 +135,7 @@ static unsigned long dynamic_syminfo_off
static unsigned int dynamic_syminfo_nent;
static char program_interpreter[64];
static bfd_vma dynamic_info[DT_JMPREL + 1];
+static bfd_vma dynamic_info_DT_GNU_HASH;
static bfd_vma version_info[16];
static Elf_Internal_Ehdr elf_header;
static Elf_Internal_Shdr *section_headers;
@@ -1501,6 +1502,7 @@ get_dynamic_type (unsigned long type)
case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ";
case DT_GNU_LIBLIST: return "GNU_LIBLIST";
case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ";
+ case DT_GNU_HASH: return "GNU_HASH";
default:
if ((type >= DT_LOPROC) && (type <= DT_HIPROC))
@@ -2571,6 +2573,7 @@ get_section_type_name (unsigned int sh_t
case SHT_INIT_ARRAY: return "INIT_ARRAY";
case SHT_FINI_ARRAY: return "FINI_ARRAY";
case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY";
+ case SHT_GNU_HASH: return "GNU_HASH";
case SHT_GROUP: return "GROUP";
case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICIES";
case SHT_GNU_verdef: return "VERDEF";
@@ -6228,6 +6231,15 @@ process_dynamic_section (FILE *file)
}
break;
+ case DT_GNU_HASH:
+ dynamic_info_DT_GNU_HASH = entry->d_un.d_val;
+ if (do_dynamic)
+ {
+ print_vma (entry->d_un.d_val, PREFIX_HEX);
+ putchar ('\n');
+ }
+ break;
+
default:
if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM))
version_info[DT_VERSIONTAGIDX (entry->d_tag)] =
@@ -6903,6 +6915,9 @@ process_symbol_table (FILE *file)
bfd_vma nchains = 0;
bfd_vma *buckets = NULL;
bfd_vma *chains = NULL;
+ bfd_vma ngnubuckets = 0;
+ bfd_vma *gnubuckets = NULL;
+ bfd_vma *gnuchains = NULL;
if (! do_syms && !do_histogram)
return 1;
@@ -7282,6 +7297,167 @@ process_symbol_table (FILE *file)
free (chains);
}
+ if (do_histogram && dynamic_info_DT_GNU_HASH)
+ {
+ unsigned char nb[12];
+ bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords;
+ unsigned long *lengths;
+ unsigned long *counts;
+ unsigned long hn;
+ unsigned long maxlength = 0;
+ unsigned long nzero_counts = 0;
+ unsigned long nsyms = 0;
+
+ if (fseek (file,
+ (archive_file_offset
+ + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
+ sizeof nb)),
+ SEEK_SET))
+ {
+ error (_("Unable to seek to start of dynamic information"));
+ return 0;
+ }
+
+ if (fread (nb, 12, 1, file) != 1)
+ {
+ error (_("Failed to read in number of buckets\n"));
+ return 0;
+ }
+
+ ngnubuckets = byte_get (nb, 4);
+ symidx = byte_get (nb + 4, 4);
+ bitmaskwords = byte_get (nb + 8, 4);
+
+ if (fseek (file,
+ (archive_file_offset
+ + offset_from_vma (file,
+ dynamic_info_DT_GNU_HASH
+ + 4 * (3 + bitmaskwords), 4)),
+ SEEK_SET))
+ {
+ error (_("Unable to seek to start of dynamic information"));
+ return 0;
+ }
+
+ gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
+
+ if (gnubuckets == NULL)
+ return 0;
+
+ for (i = 0; i < ngnubuckets; i++)
+ if (gnubuckets[i] != 0)
+ {
+ if (gnubuckets[i] < symidx)
+ return 0;
+
+ if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
+ maxchain = gnubuckets[i];
+ }
+
+ if (maxchain == 0xffffffff)
+ return 0;
+
+ maxchain -= symidx;
+
+ if (fseek (file,
+ (archive_file_offset
+ + offset_from_vma (file,
+ dynamic_info_DT_GNU_HASH
+ + 4 * (3 + bitmaskwords +
+ ngnubuckets + maxchain), 4)),
+ SEEK_SET))
+ {
+ error (_("Unable to seek to start of dynamic information"));
+ return 0;
+ }
+
+ do
+ {
+ if (fread (nb, 4, 1, file) != 1)
+ {
+ error (_("Failed to determine last chain length\n"));
+ return 0;
+ }
+
+ if (maxchain + 1 == 0)
+ return 0;
+
+ ++maxchain;
+ }
+ while ((byte_get (nb, 4) & 1) == 0);
+
+ if (fseek (file,
+ (archive_file_offset
+ + offset_from_vma (file,
+ dynamic_info_DT_GNU_HASH
+ + 4 * (3 + bitmaskwords
+ + ngnubuckets), 4)),
+ SEEK_SET))
+ {
+ error (_("Unable to seek to start of dynamic information"));
+ return 0;
+ }
+
+ gnuchains = get_dynamic_data (file, maxchain, 4);
+
+ if (gnuchains == NULL)
+ return 0;
+
+ lengths = calloc (ngnubuckets, sizeof (*lengths));
+ if (lengths == NULL)
+ {
+ error (_("Out of memory"));
+ return 0;
+ }
+
+ printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"),
+ (unsigned long) ngnubuckets);
+ printf (_(" Length Number %% of total Coverage\n"));
+
+ for (hn = 0; hn < ngnubuckets; ++hn)
+ if (gnubuckets[hn] != 0)
+ {
+ bfd_vma off, length = 1;
+
+ for (off = gnubuckets[hn] - symidx;
+ (gnuchains[off] & 1) == 0; ++off)
+ ++length;
+ lengths[hn] = length;
+ if (length > maxlength)
+ maxlength = length;
+ nsyms += length;
+ }
+
+ counts = calloc (maxlength + 1, sizeof (*counts));
+ if (counts == NULL)
+ {
+ error (_("Out of memory"));
+ return 0;
+ }
+
+ for (hn = 0; hn < ngnubuckets; ++hn)
+ ++counts[lengths[hn]];
+
+ if (ngnubuckets > 0)
+ {
+ unsigned long j;
+ printf (" 0 %-10lu (%5.1f%%)\n",
+ counts[0], (counts[0] * 100.0) / ngnubuckets);
+ for (j = 1; j <= maxlength; ++j)
+ {
+ nzero_counts += counts[j] * j;
+ printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n",
+ j, counts[j], (counts[j] * 100.0) / ngnubuckets,
+ (nzero_counts * 100.0) / nsyms);
+ }
+ }
+
+ free (counts);
+ free (lengths);
+ free (gnubuckets);
+ free (gnuchains);
+ }
+
return 1;
}
[-- Attachment #3: glibc-gnu-hash.patch --]
[-- Type: text/plain, Size: 20423 bytes --]
2006-07-07 Ulrich Drepper <drepper@redhat.com>
* elf/dl-lookup.c (dl_new_hash): New functions.
(_dl_lookup_symbol_x): Rename hash to old_hash and don't compute
value here. Compute new-style hash value. Pass new hash value
and reference to variable with the old value to do_lookup_x.
(_dl_setup_hash): If DT_GNU_HASH is defined, use it and not
old-style hash table.
(_dl_debug_bindings): Pass new hash value and reference to variable
with the old value to do_lookup_x.
* elf/do-lookup.h (do_lookup_x): Accept additional parameter with
new-style hash value and change old-style hash value parameter to
be a reference. Reoganize functions to determine whether
new-style hash table is available. Only fall back on old-style
table. If old-style hash value is needed, compute it here.
* elf/dynamic-link.h (elf_get_dynamic_info): Relocate DT_GNU_HASH
entry.
* elf/elf.h: Define SHT_GNU_HASH, DT_GNU_HASH, DT_TLSDEC_PLT,
DT_TLSDEC_GOT. Adjust DT_ADDRNUM.
* include/link.h (struct link_map): Add l_gnu_buckets,
l_gnu_chain_zero, l_gnu_bitmask and l_gnu_mask fields.
* Makeconfig: If linker supports --hash-style option add it to all
linker command lines to build DSOs.
* config.make.in: Define have-hash-style.
* configure.in: Test whether linker supports --hash-style option.
--- libc/Makeconfig.~1.318.~ 2006-05-15 11:21:55.000000000 -0700
+++ libc/Makeconfig 2006-07-06 10:13:00.000000000 -0700
@@ -413,11 +413,20 @@ LDFLAGS.so += $(relro-LDFLAGS)
LDFLAGS-rtld += $(relro-LDFLAGS)
endif
+ifeq (yes,$(have-hash-style))
+# For the time being we unconditionally use 'both'. At some time we
+# should declare statically linked code as 'out of luck' and compile
+# with --hash-style=gnu only.
+hashstyle-LDFLAGS = -Wl,--hash-style=both
+LDFLAGS.so += $(hashstyle-LDFLAGS)
+LDFLAGS-rtld += $(hashstyle-LDFLAGS)
+endif
+
# Command for linking programs with the C library.
ifndef +link
+link = $(CC) -nostdlib -nostartfiles -o $@ \
$(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
- $(combreloc-LDFLAGS) $(relro-LDFLAGS) \
+ $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
$(addprefix $(csu-objpfx),$(start-installed-name)) \
$(+preinit) $(+prector) \
$(filter-out $(addprefix $(csu-objpfx),start.o \
--- libc/config.make.in.~1.118.~ 2006-04-26 08:17:41.000000000 -0700
+++ libc/config.make.in 2006-06-27 05:38:40.000000000 -0700
@@ -65,6 +65,7 @@ have-libcap = @have_libcap@
have-cc-with-libunwind = @libc_cv_cc_with_libunwind@
fno-unit-at-a-time = @fno_unit_at_a_time@
bind-now = @bindnow@
+have-hash-style = @libc_cv_hashstyle@
static-libgcc = @libc_cv_gcc_static_libgcc@
--- libc/configure.in.~1.460.~ 2006-04-26 08:19:22.000000000 -0700
+++ libc/configure.in 2006-06-26 13:47:01.000000000 -0700
@@ -1589,6 +1589,22 @@ EOF
rm -f conftest*])
AC_SUBST(libc_cv_fpie)
+
+ AC_CACHE_CHECK(for --hash-style option,
+ libc_cv_hashstyle, [dnl
+ cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+ if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+ -fPIC -shared -o conftest.so conftest.c
+ -Wl,--hash-style=both -nostdlib 1>&AS_MESSAGE_LOG_FD])
+ then
+ libc_cv_hashstyle=yes
+ else
+ libc_cv_hashstyle=no
+ fi
+ rm -f conftest*])
+ AC_SUBST(libc_cv_hashstyle)
fi
AC_CACHE_CHECK(for -fno-toplevel-reorder, libc_cv_fno_toplevel_reorder, [dnl
--- libc/elf/dynamic-link.h.jj 2006-03-17 08:55:20.000000000 +0100
+++ libc/elf/dynamic-link.h 2006-07-07 00:00:49.000000000 +0200
@@ -1,5 +1,5 @@
/* Inline functions for dynamic linking.
- Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -143,6 +143,8 @@ elf_get_dynamic_info (struct link_map *l
# endif
ADJUST_DYN_INFO (DT_JMPREL);
ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
+ ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
# undef ADJUST_DYN_INFO
assert (cnt <= DL_RO_DYN_TEMP_CNT);
}
--- libc/elf/elf.h.jj 2006-02-28 15:13:56.000000000 +0100
+++ libc/elf/elf.h 2006-07-07 00:00:49.000000000 +0200
@@ -329,7 +329,8 @@ typedef struct
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
#define SHT_NUM 19 /* Number of defined types. */
-#define SHT_LOOS 0x60000000 /* Start OS-specific */
+#define SHT_LOOS 0x60000000 /* Start OS-specific. */
+#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
@@ -699,6 +700,9 @@ typedef struct
If any adjustment is made to the ELF object after it has been
built these entries will need to be adjusted. */
#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
#define DT_CONFIG 0x6ffffefa /* Configuration information. */
@@ -709,7 +713,7 @@ typedef struct
#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
#define DT_ADDRRNGHI 0x6ffffeff
#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
-#define DT_ADDRNUM 10
+#define DT_ADDRNUM 11
/* The versioning entry types. The next are defined as part of the
GNU extension. */
--- libc/elf/dl-lookup.c.jj 2005-12-27 11:56:45.000000000 +0100
+++ libc/elf/dl-lookup.c 2006-07-07 16:22:04.000000000 +0200
@@ -1,5 +1,5 @@
/* Look up a symbol in the loaded objects.
- Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -72,6 +72,16 @@ struct sym_val
#include "do-lookup.h"
+static uint_fast32_t
+dl_new_hash (const char *s)
+{
+ uint_fast32_t h = 5381;
+ for (unsigned char c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
+
+
/* Add extra dependency on MAP to UNDEF_MAP. */
static int
internal_function
@@ -206,7 +216,8 @@ _dl_lookup_symbol_x (const char *undef_n
const struct r_found_version *version,
int type_class, int flags, struct link_map *skip_map)
{
- const unsigned long int hash = _dl_elf_hash (undef_name);
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope = symbol_scope;
@@ -229,8 +240,9 @@ _dl_lookup_symbol_x (const char *undef_n
/* Search the relevant loaded objects for a definition. */
for (size_t start = i; *scope != NULL; start = 0, ++scope)
{
- int res = do_lookup_x (undef_name, hash, *ref, ¤t_value, *scope,
- start, version, flags, skip_map, type_class);
+ int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ ¤t_value, *scope, start, version, flags,
+ skip_map, type_class);
if (res > 0)
break;
@@ -301,9 +313,9 @@ _dl_lookup_symbol_x (const char *undef_n
struct sym_val protected_value = { NULL, NULL };
for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
- if (do_lookup_x (undef_name, hash, *ref, &protected_value,
- *scope, i, version, flags, skip_map,
- ELF_RTYPE_CLASS_PLT) != 0)
+ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &protected_value, *scope, i, version, flags,
+ skip_map, ELF_RTYPE_CLASS_PLT) != 0)
break;
if (protected_value.s != NULL && protected_value.m != undef_map)
@@ -352,6 +364,26 @@ _dl_setup_hash (struct link_map *map)
Elf_Symndx *hash;
Elf_Symndx nchain;
+ if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM] != NULL, 1))
+ {
+ Elf32_Word *hash32
+ = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM]);
+ map->l_nbuckets = *hash32++;
+ Elf32_Word symbias = *hash32++;
+ Elf32_Word maskwords = *hash32++;
+ map->l_gnu_bitmask = hash32;
+ hash32 += maskwords;
+ map->l_gnu_buckets = hash32;
+ hash32 += map->l_nbuckets;
+ map->l_gnu_chain_zero = hash32 - symbias;
+ map->l_gnu_mask = maskwords - 1;
+ return;
+ }
+
if (!map->l_info[DT_HASH])
return;
hash = (void *) D_PTR (map, l_info[DT_HASH]);
@@ -399,9 +431,10 @@ _dl_debug_bindings (const char *undef_na
|| GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
&& undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded)
{
- const unsigned long int hash = _dl_elf_hash (undef_name);
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
- do_lookup_x (undef_name, hash, *ref, &val,
+ do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
undef_map->l_local_scope[0], 0, version, 0, NULL,
type_class);
--- libc/elf/do-lookup.h.jj 2006-02-28 15:13:56.000000000 +0100
+++ libc/elf/do-lookup.h 2006-07-07 16:24:19.000000000 +0200
@@ -17,32 +17,29 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+
/* Inner part of the lookup functions. We return a value > 0 if we
found the symbol, the value 0 if nothing is found and < 0 if
something bad happened. */
static int
__attribute_noinline__
-do_lookup_x (const char *undef_name, unsigned long int hash,
- const ElfW(Sym) *ref, struct sym_val *result,
- struct r_scope_elem *scope, size_t i,
+do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ unsigned long int *old_hash, const ElfW(Sym) *ref,
+ struct sym_val *result, struct r_scope_elem *scope, size_t i,
const struct r_found_version *const version, int flags,
struct link_map *skip, int type_class)
{
struct link_map **list = scope->r_list;
size_t n = scope->r_nlist;
- struct link_map *map;
do
{
- const ElfW(Sym) *symtab;
- const char *strtab;
- const ElfW(Half) *verstab;
+ /* These variables are used in the nested function. */
Elf_Symndx symidx;
- const ElfW(Sym) *sym;
int num_versions = 0;
const ElfW(Sym) *versioned_sym = NULL;
- map = list[i]->l_real;
+ struct link_map *map = list[i]->l_real;
/* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
if (map == skip)
@@ -63,109 +60,143 @@ do_lookup_x (const char *undef_name, uns
map->l_name[0] ? map->l_name : rtld_progname,
map->l_ns);
- symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
- strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
- verstab = map->l_versyms;
-
- /* Search the appropriate hash bucket in this object's symbol table
- for a definition for the same symbol name. */
- for (symidx = map->l_buckets[hash % map->l_nbuckets];
- symidx != STN_UNDEF;
- symidx = map->l_chain[symidx])
- {
- sym = &symtab[symidx];
-
- assert (ELF_RTYPE_CLASS_PLT == 1);
- if ((sym->st_value == 0 /* No value. */
-#ifdef USE_TLS
- && ELFW(ST_TYPE) (sym->st_info) != STT_TLS
-#endif
- )
- || (type_class & (sym->st_shndx == SHN_UNDEF)))
- continue;
-
- if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
-#ifdef USE_TLS
- && ELFW(ST_TYPE) (sym->st_info) != STT_TLS
-#endif
- )
- /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
- entries (and STT_TLS if TLS is supported) since these
- are no code/data definitions. */
- continue;
-
- if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
- /* Not the symbol we are looking for. */
- continue;
+ /* The tables for this map. */
+ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ const ElfW(Half) *verstab = map->l_versyms;
+
+ /* Nested routine to check whether the symbol matches. */
+ const ElfW(Sym) *
+ __attribute_noinline__
+ check_match (const ElfW(Sym) *sym)
+ {
+ assert (ELF_RTYPE_CLASS_PLT == 1);
+ if (__builtin_expect ((sym->st_value == 0 /* No value. */
+ && ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
+ || (type_class & (sym->st_shndx == SHN_UNDEF)),
+ 0))
+ return NULL;
+
+ if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
+ && ELFW(ST_TYPE) (sym->st_info) != STT_TLS, 0))
+ /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
+ entries (and STT_TLS if TLS is supported) since these
+ are no code/data definitions. */
+ return NULL;
+
+ if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+ /* Not the symbol we are looking for. */
+ return NULL;
+
+ if (version != NULL)
+ {
+ if (__builtin_expect (verstab == NULL, 0))
+ {
+ /* We need a versioned symbol but haven't found any. If
+ this is the object which is referenced in the verneed
+ entry it is a bug in the library since a symbol must
+ not simply disappear.
+
+ It would also be a bug in the object since it means that
+ the list of required versions is incomplete and so the
+ tests in dl-version.c haven't found a problem.*/
+ assert (version->filename == NULL
+ || ! _dl_name_match_p (version->filename, map));
+
+ /* Otherwise we accept the symbol. */
+ }
+ else
+ {
+ /* We can match the version information or use the
+ default one if it is not hidden. */
+ ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+ if ((map->l_versions[ndx].hash != version->hash
+ || strcmp (map->l_versions[ndx].name, version->name))
+ && (version->hidden || map->l_versions[ndx].hash
+ || (verstab[symidx] & 0x8000)))
+ /* It's not the version we want. */
+ return NULL;
+ }
+ }
+ else
+ {
+ /* No specific version is selected. There are two ways we
+ can got here:
+
+ - a binary which does not include versioning information
+ is loaded
+
+ - dlsym() instead of dlvsym() is used to get a symbol which
+ might exist in more than one form
+
+ If the library does not provide symbol version information
+ there is no problem at at: we simply use the symbol if it
+ is defined.
+
+ These two lookups need to be handled differently if the
+ library defines versions. In the case of the old
+ unversioned application the oldest (default) version
+ should be used. In case of a dlsym() call the latest and
+ public interface should be returned. */
+ if (verstab != NULL)
+ {
+ if ((verstab[symidx] & 0x7fff)
+ >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
+ {
+ /* Don't accept hidden symbols. */
+ if ((verstab[symidx] & 0x8000) == 0
+ && num_versions++ == 0)
+ /* No version so far. */
+ versioned_sym = sym;
+
+ return NULL;
+ }
+ }
+ }
+
+ /* There cannot be another entry for this symbol so stop here. */
+ return sym;
+ }
- if (version != NULL)
+ const ElfW(Sym) *sym;
+ if (__builtin_expect (map->l_gnu_buckets != NULL, 1))
+ {
+ if ((map->l_gnu_bitmask[(new_hash >> 5) & map->l_gnu_mask]
+ & (1 << (new_hash & 31))) != 0)
{
- if (__builtin_expect (verstab == NULL, 0))
+ Elf32_Word chainoff = map->l_gnu_buckets[new_hash % map->l_nbuckets];
+ if (chainoff != 0xffffffff)
{
- /* We need a versioned symbol but haven't found any. If
- this is the object which is referenced in the verneed
- entry it is a bug in the library since a symbol must
- not simply disappear.
-
- It would also be a bug in the object since it means that
- the list of required versions is incomplete and so the
- tests in dl-version.c haven't found a problem.*/
- assert (version->filename == NULL
- || ! _dl_name_match_p (version->filename, map));
+ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[chainoff];
- /* Otherwise we accept the symbol. */
- }
- else
- {
- /* We can match the version information or use the
- default one if it is not hidden. */
- ElfW(Half) ndx = verstab[symidx] & 0x7fff;
- if ((map->l_versions[ndx].hash != version->hash
- || strcmp (map->l_versions[ndx].name, version->name))
- && (version->hidden || map->l_versions[ndx].hash
- || (verstab[symidx] & 0x8000)))
- /* It's not the version we want. */
- continue;
+ do
+ if ((*hasharr & ~1u) == (new_hash & ~1u))
+ {
+ symidx = hasharr - map->l_gnu_chain_zero;
+ sym = check_match (&symtab[symidx]);
+ if (sym != NULL)
+ goto found_it;
+ }
+ while ((*hasharr++ & 1u) == 0);
}
}
- else
- {
- /* No specific version is selected. There are two ways we
- can got here:
-
- - a binary which does not include versioning information
- is loaded
-
- - dlsym() instead of dlvsym() is used to get a symbol which
- might exist in more than one form
-
- If the library does not provide symbol version
- information there is no problem at at: we simply use the
- symbol if it is defined.
-
- These two lookups need to be handled differently if the
- library defines versions. In the case of the old
- unversioned application the oldest (default) version
- should be used. In case of a dlsym() call the latest and
- public interface should be returned. */
- if (verstab != NULL)
- {
- if ((verstab[symidx] & 0x7fff)
- >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
- {
- /* Don't accept hidden symbols. */
- if ((verstab[symidx] & 0x8000) == 0
- && num_versions++ == 0)
- /* No version so far. */
- versioned_sym = sym;
+ }
+ else
+ {
+ if (*old_hash == 0xffffffff)
+ *old_hash = _dl_elf_hash (undef_name);
- continue;
- }
- }
+ /* Use the old SysV-style hash table. Search the appropriate
+ hash bucket in this object's symbol table for a definition
+ for the same symbol name. */
+ for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ sym = check_match (&symtab[symidx]);
+ if (sym != NULL)
+ goto found_it;
}
-
- /* There cannot be another entry for this symbol so stop here. */
- goto found_it;
}
/* If we have seen exactly one versioned symbol while we are
@@ -213,7 +244,3 @@ do_lookup_x (const char *undef_name, uns
/* We have not found anything until now. */
return 0;
}
-
-#undef FCT
-#undef ARG
-#undef VERSIONED
--- libc/include/link.h.jj 2006-03-03 14:31:38.000000000 +0100
+++ libc/include/link.h 2006-07-07 00:03:13.000000000 +0200
@@ -124,7 +124,7 @@ struct link_map
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */
ElfW(Addr) l_entry; /* Entry point location. */
ElfW(Half) l_phnum; /* Number of program header entries. */
- ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */
+ ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */
/* Array of DT_NEEDED dependencies and their dependencies, in
dependency order for symbol lookup (with and without
@@ -141,7 +141,18 @@ struct link_map
/* Symbol hash table. */
Elf_Symndx l_nbuckets;
- const Elf_Symndx *l_buckets, *l_chain;
+ const Elf32_Word *l_gnu_buckets;
+ union
+ {
+ const Elf32_Word *l_gnu_chain_zero;
+ const Elf_Symndx *l_chain;
+ };
+ union
+ {
+ const Elf32_Word *l_gnu_bitmask;
+ const Elf_Symndx *l_buckets;
+ };
+ Elf32_Word l_gnu_mask;
unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose. */
enum /* Where this object came from. */
[-- Attachment #4: statsn --]
[-- Type: text/plain, Size: 14597 bytes --]
cat > a.c <<\EOF
cat /tmp/a.c
#include <dlfcn.h>
const char *libs[] = {
"libvclplug_gtk680lx.so", "libvclplug_gen680lx.so", "libnss_files.so.2",
"libGL.so.1", "servicemgr.uno.so",
"shlibloader.uno.so", "simplereg.uno.so", "nestedreg.uno.so",
"typemgr.uno.so", "implreg.uno.so",
"security.uno.so", "libreg.so.3", "libstore.so.3", "regtypeprov.uno.so",
"configmgr2.uno.so",
"typeconverter.uno.so", "gconfbe1.uno.so", "behelper.uno.so", "sax.uno.so",
"localebe1.uno.so",
"uriproc.uno.so", "libspl680lx.so", "libucb1.so", "ucpgvfs1.uno.so",
"libgcc3_uno.so", "libpackage2.so",
"libfileacc.so", "libuui680lx.so", "libfilterconfig1.so",
"libdtransX11680lx.so", "i18npool.uno.so",
"liblocaledata_en.so", "fsstorage.uno.so", "libxstor.so",
"libdbtools680lx.so", "libcups.so.2",
"libgnutls.so.13", "libgcrypt.so.11", "libgpg-error.so.0", "libmcnttype.so",
"libucpchelp1.so",
"svtmisc.uno.so" };
int
main (int argc, char **argv)
{
int i;
void *h;
int flags = RTLD_LAZY;
if (argv[1][0] == 'g')
flags |= RTLD_GLOBAL;
for (i = 0; i < sizeof (libs) / sizeof (libs[0]); ++i)
h = dlopen (libs[i], flags);
return 0;
}
EOF
gcc -g -O2 -o a a.c -Wl,-rpath,/usr/lib64/openoffice.org2.0/program/ \
-L/usr/lib64/openoffice.org2.0/program/ -lsoffice -lsw680lx -lsvx680lx -lstdc++ -lm -shared-libgcc
for V in local global; do for M in '' 'export LD_X=1' 'export LD_BIND_NOW=1' 'export LD_X=1 LD_BIND_NOW=1'; \
do ( for i in 1 2 3 4; do eval $M; time ./a $V; done 2>&1 > /dev/null | \
awk 'BEGIN { printf "'"$V $M"'\t" } /^real/ { printf "%s ", $2 } END { printf "\n" }' ); done; done
take4
local 0m0.180s 0m0.175s 0m0.174s 0m0.174s
local export LD_X=1 0m0.591s 0m0.593s 0m0.593s 0m0.603s
local export LD_BIND_NOW=1 0m0.306s 0m0.303s 0m0.309s 0m0.303s
local export LD_X=1 LD_BIND_NOW=1 0m1.186s 0m1.188s 0m1.146s 0m1.149s
global 0m0.203s 0m0.198s 0m0.201s 0m0.198s
global export LD_X=1 0m0.669s 0m0.686s 0m0.673s 0m0.672s
global export LD_BIND_NOW=1 0m0.354s 0m0.349s 0m0.347s 0m0.348s
global export LD_X=1 LD_BIND_NOW=1 0m1.334s 0m1.347s 0m1.356s 0m1.379s
for V in local global; do for M in '' 'export LD_X=1' 'export LD_BIND_NOW=1' 'export LD_X=1 LD_BIND_NOW=1'; \
do ( echo "$V $M"; eval $M; valgrind --tool=cachegrind ./a $V 2>&1 > /dev/null | sed -n '/== I refs/,$p' ); \
done; done
take4
local
==22333== I refs: 201,078,072
==22333== I1 misses: 11,304
==22333== L2i misses: 9,911
==22333== I1 miss rate: 0.00%
==22333== L2i miss rate: 0.00%
==22333==
==22333== D refs: 74,797,589 (58,315,275 rd + 16,482,314 wr)
==22333== D1 misses: 3,404,397 ( 3,256,012 rd + 148,385 wr)
==22333== L2d misses: 489,312 ( 398,103 rd + 91,209 wr)
==22333== D1 miss rate: 4.5% ( 5.5% + 0.9% )
==22333== L2d miss rate: 0.6% ( 0.6% + 0.5% )
==22333==
==22333== L2 refs: 3,415,701 ( 3,267,316 rd + 148,385 wr)
==22333== L2 misses: 499,223 ( 408,014 rd + 91,209 wr)
==22333== L2 miss rate: 0.1% ( 0.1% + 0.5% )
local export LD_X=1
==22337== I refs: 311,492,449
==22337== I1 misses: 11,299
==22337== L2i misses: 10,321
==22337== I1 miss rate: 0.00%
==22337== L2i miss rate: 0.00%
==22337==
==22337== D refs: 128,005,658 (98,076,224 rd + 29,929,434 wr)
==22337== D1 misses: 9,559,670 ( 9,395,598 rd + 164,072 wr)
==22337== L2d misses: 3,022,405 ( 2,916,644 rd + 105,761 wr)
==22337== D1 miss rate: 7.4% ( 9.5% + 0.5% )
==22337== L2d miss rate: 2.3% ( 2.9% + 0.3% )
==22337==
==22337== L2 refs: 9,570,969 ( 9,406,897 rd + 164,072 wr)
==22337== L2 misses: 3,032,726 ( 2,926,965 rd + 105,761 wr)
==22337== L2 miss rate: 0.6% ( 0.7% + 0.3% )
local export LD_BIND_NOW=1
==22341== I refs: 389,236,554
==22341== I1 misses: 10,837
==22341== L2i misses: 9,717
==22341== I1 miss rate: 0.00%
==22341== L2i miss rate: 0.00%
==22341==
==22341== D refs: 148,524,589 (115,298,089 rd + 33,226,500 wr)
==22341== D1 misses: 6,929,319 ( 6,754,195 rd + 175,124 wr)
==22341== L2d misses: 657,766 ( 559,064 rd + 98,702 wr)
==22341== D1 miss rate: 4.6% ( 5.8% + 0.5% )
==22341== L2d miss rate: 0.4% ( 0.4% + 0.2% )
==22341==
==22341== L2 refs: 6,940,156 ( 6,765,032 rd + 175,124 wr)
==22341== L2 misses: 667,483 ( 568,781 rd + 98,702 wr)
==22341== L2 miss rate: 0.1% ( 0.1% + 0.2% )
local export LD_X=1 LD_BIND_NOW=1
==22345== I refs: 622,558,758
==22345== I1 misses: 10,829
==22345== L2i misses: 9,927
==22345== I1 miss rate: 0.00%
==22345== L2i miss rate: 0.00%
==22345==
==22345== D refs: 262,006,683 (199,686,725 rd + 62,319,958 wr)
==22345== D1 misses: 20,358,555 ( 20,138,179 rd + 220,376 wr)
==22345== L2d misses: 6,288,581 ( 6,175,041 rd + 113,540 wr)
==22345== D1 miss rate: 7.7% ( 10.0% + 0.3% )
==22345== L2d miss rate: 2.4% ( 3.0% + 0.1% )
==22345==
==22345== L2 refs: 20,369,384 ( 20,149,008 rd + 220,376 wr)
==22345== L2 misses: 6,298,508 ( 6,184,968 rd + 113,540 wr)
==22345== L2 miss rate: 0.7% ( 0.7% + 0.1% )
global
==22349== I refs: 216,049,983
==22349== I1 misses: 11,443
==22349== L2i misses: 10,043
==22349== I1 miss rate: 0.00%
==22349== L2i miss rate: 0.00%
==22349==
==22349== D refs: 82,419,601 (64,203,003 rd + 18,216,598 wr)
==22349== D1 misses: 5,154,627 ( 5,004,907 rd + 149,720 wr)
==22349== L2d misses: 500,196 ( 408,675 rd + 91,521 wr)
==22349== D1 miss rate: 6.2% ( 7.7% + 0.8% )
==22349== L2d miss rate: 0.6% ( 0.6% + 0.5% )
==22349==
==22349== L2 refs: 5,166,070 ( 5,016,350 rd + 149,720 wr)
==22349== L2 misses: 510,239 ( 418,718 rd + 91,521 wr)
==22349== L2 miss rate: 0.1% ( 0.1% + 0.5% )
global export LD_X=1
==22353== I refs: 337,282,635
==22353== I1 misses: 11,425
==22353== L2i misses: 10,469
==22353== I1 miss rate: 0.00%
==22353== L2i miss rate: 0.00%
==22353==
==22353== D refs: 141,116,515 (107,952,083 rd + 33,164,432 wr)
==22353== D1 misses: 12,018,123 ( 11,852,619 rd + 165,504 wr)
==22353== L2d misses: 3,503,191 ( 3,396,933 rd + 106,258 wr)
==22353== D1 miss rate: 8.5% ( 10.9% + 0.4% )
==22353== L2d miss rate: 2.4% ( 3.1% + 0.3% )
==22353==
==22353== L2 refs: 12,029,548 ( 11,864,044 rd + 165,504 wr)
==22353== L2 misses: 3,513,660 ( 3,407,402 rd + 106,258 wr)
==22353== L2 miss rate: 0.7% ( 0.7% + 0.3% )
global export LD_BIND_NOW=1
==22359== I refs: 416,388,279
==22359== I1 misses: 10,963
==22359== L2i misses: 9,841
==22359== I1 miss rate: 0.00%
==22359== L2i miss rate: 0.00%
==22359==
==22359== D refs: 162,316,098 (125,953,786 rd + 36,362,312 wr)
==22359== D1 misses: 10,111,441 ( 9,932,496 rd + 178,945 wr)
==22359== L2d misses: 675,000 ( 575,984 rd + 99,016 wr)
==22359== D1 miss rate: 6.2% ( 7.8% + 0.4% )
==22359== L2d miss rate: 0.4% ( 0.4% + 0.2% )
==22359==
==22359== L2 refs: 10,122,404 ( 9,943,459 rd + 178,945 wr)
==22359== L2 misses: 684,841 ( 585,825 rd + 99,016 wr)
==22359== L2 miss rate: 0.1% ( 0.1% + 0.2% )
global export LD_X=1 LD_BIND_NOW=1
==22363== I refs: 668,842,809
==22363== I1 misses: 10,942
==22363== L2i misses: 10,052
==22363== I1 miss rate: 0.00%
==22363== L2i miss rate: 0.00%
==22363==
==22363== D refs: 285,593,622 (217,433,359 rd + 68,160,263 wr)
==22363== D1 misses: 24,793,665 ( 24,570,244 rd + 223,421 wr)
==22363== L2d misses: 7,189,812 ( 7,075,786 rd + 114,026 wr)
==22363== D1 miss rate: 8.6% ( 11.3% + 0.3% )
==22363== L2d miss rate: 2.5% ( 3.2% + 0.1% )
==22363==
==22363== L2 refs: 24,804,607 ( 24,581,186 rd + 223,421 wr)
==22363== L2 misses: 7,199,864 ( 7,085,838 rd + 114,026 wr)
==22363== L2 miss rate: 0.7% ( 0.7% + 0.1% )
for V in local global; do for M in '' '-E LD_X=1' '-E LD_BIND_NOW=1' '-E LD_X=1 -E LD_BIND_NOW=1'; \
do ( echo "$V $M"; ./timing $M ./a $V ); done; done
take4
local
Strip out best and worst realtime result
minimum: 0.171330000 sec real / 0.000059879 sec CPU
maximum: 0.183637000 sec real / 0.000140912 sec CPU
average: 0.173522535 sec real / 0.000065315 sec CPU
stdev : 0.000694442 sec real / 0.000000770 sec CPU
local -E LD_X=1
optarg="LD_X=1"
Strip out best and worst realtime result
minimum: 0.575774000 sec real / 0.000053405 sec CPU
maximum: 0.595938000 sec real / 0.000079537 sec CPU
average: 0.587580821 sec real / 0.000075442 sec CPU
stdev : 0.004159043 sec real / 0.000001989 sec CPU
local -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.299670000 sec real / 0.000055573 sec CPU
maximum: 0.306395000 sec real / 0.000086738 sec CPU
average: 0.302749821 sec real / 0.000073164 sec CPU
stdev : 0.001761517 sec real / 0.000003183 sec CPU
local -E LD_X=1 -E LD_BIND_NOW=1
optarg="LD_X=1"
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 1.162265000 sec real / 0.000055101 sec CPU
maximum: 1.209383000 sec real / 0.000073149 sec CPU
average: 1.189671071 sec real / 0.000065435 sec CPU
stdev : 0.007947359 sec real / 0.000000731 sec CPU
global
Strip out best and worst realtime result
minimum: 0.195825000 sec real / 0.000064238 sec CPU
maximum: 0.198755000 sec real / 0.000069930 sec CPU
average: 0.197095571 sec real / 0.000065329 sec CPU
stdev : 0.000657043 sec real / 0.000000924 sec CPU
global -E LD_X=1
optarg="LD_X=1"
Strip out best and worst realtime result
minimum: 0.658855000 sec real / 0.000052899 sec CPU
maximum: 0.693884000 sec real / 0.000084485 sec CPU
average: 0.676305857 sec real / 0.000076110 sec CPU
stdev : 0.004805411 sec real / 0.000003079 sec CPU
global -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.342948000 sec real / 0.000054621 sec CPU
maximum: 0.353243000 sec real / 0.000080357 sec CPU
average: 0.347779142 sec real / 0.000073702 sec CPU
stdev : 0.002035106 sec real / 0.000003696 sec CPU
global -E LD_X=1 -E LD_BIND_NOW=1
optarg="LD_X=1"
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 1.314006000 sec real / 0.000053499 sec CPU
maximum: 1.400049000 sec real / 0.000070065 sec CPU
average: 1.346385214 sec real / 0.000065079 sec CPU
stdev : 0.012294494 sec real / 0.000000950 sec CPU
/usr/sbin/prelink -vmR ./a
for V in local global; do for M in '' 'export LD_X=1' 'export LD_BIND_NOW=1' 'export LD_X=1 LD_BIND_NOW=1'; \
do ( for i in 1 2 3 4; do eval $M; time ./a $V; done 2>&1 > /dev/null | \
awk 'BEGIN { printf "'"$V $M"'\t" } /^real/ { printf "%s ", $2 } END { printf "\n" }' ); done; done
take4
local 0m0.110s 0m0.090s 0m0.090s 0m0.089s
local export LD_X=1 0m0.287s 0m0.279s 0m0.285s 0m0.277s
local export LD_BIND_NOW=1 0m0.147s 0m0.145s 0m0.143s 0m0.143s
local export LD_X=1 LD_BIND_NOW=1 0m0.547s 0m0.535s 0m0.533s 0m0.527s
global 0m0.115s 0m0.112s 0m0.113s 0m0.113s
global export LD_X=1 0m0.368s 0m0.374s 0m0.360s 0m0.356s
global export LD_BIND_NOW=1 0m0.187s 0m0.185s 0m0.185s 0m0.185s
global export LD_X=1 LD_BIND_NOW=1 0m0.686s 0m0.690s 0m0.667s 0m0.666s
# valgrind --tool=cachegrind stats not provided for prelinked testcase,
# as valgrind apparently uses LD_PRELOAD internally and thus prevents
# prelinking.
for V in local global; do for M in '' '-E LD_X=1' '-E LD_BIND_NOW=1' '-E LD_X=1 -E LD_BIND_NOW=1'; \
do ( echo "$V $M"; ./timing $M ./a $V ); done; done
take4
local
Strip out best and worst realtime result
minimum: 0.088558000 sec real / 0.000062737 sec CPU
maximum: 0.090857000 sec real / 0.000075048 sec CPU
average: 0.089202000 sec real / 0.000064855 sec CPU
stdev : 0.000453942 sec real / 0.000002985 sec CPU
local -E LD_X=1
optarg="LD_X=1"
Strip out best and worst realtime result
minimum: 0.274995000 sec real / 0.000055459 sec CPU
maximum: 0.291724000 sec real / 0.000085829 sec CPU
average: 0.285347750 sec real / 0.000073140 sec CPU
stdev : 0.004344181 sec real / 0.000003294 sec CPU
local -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.142244000 sec real / 0.000052852 sec CPU
maximum: 0.145730000 sec real / 0.000074901 sec CPU
average: 0.143050857 sec real / 0.000063817 sec CPU
stdev : 0.000588257 sec real / 0.000000572 sec CPU
local -E LD_X=1 -E LD_BIND_NOW=1
optarg="LD_X=1"
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.516412000 sec real / 0.000052547 sec CPU
maximum: 0.551295000 sec real / 0.000080505 sec CPU
average: 0.536137714 sec real / 0.000072925 sec CPU
stdev : 0.008204213 sec real / 0.000003287 sec CPU
global
Strip out best and worst realtime result
minimum: 0.111122000 sec real / 0.000057277 sec CPU
maximum: 0.113199000 sec real / 0.000072477 sec CPU
average: 0.111739535 sec real / 0.000063569 sec CPU
stdev : 0.000365911 sec real / 0.000002389 sec CPU
global -E LD_X=1
optarg="LD_X=1"
Strip out best and worst realtime result
minimum: 0.356423000 sec real / 0.000054153 sec CPU
maximum: 0.385610000 sec real / 0.000077109 sec CPU
average: 0.369770464 sec real / 0.000072567 sec CPU
stdev : 0.005942862 sec real / 0.000003175 sec CPU
global -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.182965000 sec real / 0.000054313 sec CPU
maximum: 0.189492000 sec real / 0.000068199 sec CPU
average: 0.184005428 sec real / 0.000063653 sec CPU
stdev : 0.000723054 sec real / 0.000001477 sec CPU
global -E LD_X=1 -E LD_BIND_NOW=1
optarg="LD_X=1"
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.650583000 sec real / 0.000052562 sec CPU
maximum: 0.700625000 sec real / 0.000077906 sec CPU
average: 0.680901214 sec real / 0.000073774 sec CPU
stdev : 0.011186022 sec real / 0.000002110 sec CPU
[-- Attachment #5: statsx --]
[-- Type: text/plain, Size: 6251 bytes --]
cat > n.c <<\EOF
#include <stdlib.h>
#include <dlfcn.h>
const char *libs[] = {
"libvclplug_gtk680lx.so", "libvclplug_gen680lx.so", "libnss_files.so.2", "libGL.so.1", "servicemgr.uno.so",
"shlibloader.uno.so", "simplereg.uno.so", "nestedreg.uno.so", "typemgr.uno.so", "implreg.uno.so",
"security.uno.so", "libreg.so.3", "libstore.so.3", "regtypeprov.uno.so", "configmgr2.uno.so",
"typeconverter.uno.so", "gconfbe1.uno.so", "behelper.uno.so", "sax.uno.so", "localebe1.uno.so",
"uriproc.uno.so", "libspl680lx.so", "libucb1.so", "ucpgvfs1.uno.so", "libgcc3_uno.so", "libpackage2.so",
"libfileacc.so", "libuui680lx.so", "libfilterconfig1.so", "libdtransX11680lx.so", "i18npool.uno.so",
"liblocaledata_en.so", "fsstorage.uno.so", "libxstor.so", "libdbtools680lx.so", "libcups.so.2",
"libgnutls.so.13", "libgcrypt.so.11", "libgpg-error.so.0", "libmcnttype.so", "libucpchelp1.so",
"svtmisc.uno.so" };
int
__attribute__((noinline))
evict_cache (long *array, size_t count)
{
size_t i;
int ret = 0;
for (i = 0; i < count; i++)
array[i] = i + 1;
for (i = 0; i < count; i++)
ret += array[i];
return ret;
}
int
main (int argc, char **argv)
{
int i;
void *h;
/* Adjust for your L2 cache, mine is 1MB. */
long *array = malloc (256 * 1024 * sizeof (long));
int flags = RTLD_LAZY;
if (argv[1][0] == 'g')
flags |= RTLD_GLOBAL;
for (i = 0; i < sizeof (libs) / sizeof (libs[0]); ++i)
{
evict_cache (array, 256 * 1024);
h = dlopen (libs[i], flags);
}
return 0;
}
EOF
gcc -g -O2 -o n n.c -Wl,-rpath,/usr/lib64/openoffice.org2.0/program/ \
-L/usr/lib64/openoffice.org2.0/program/ -lsoffice -lsw680lx -lsvx680lx -lstdc++ -lm -shared-libgcc
/usr/sbin/prelink -vmR ./n
for V in local global; do for M in '' '-E LD_BIND_NOW=1'; do ( echo "$V $M"; ./timing $M ./n $V ); done; done
take1
local
Strip out best and worst realtime result
minimum: 0.252598000 sec real / 0.000068125 sec CPU
maximum: 0.255268000 sec real / 0.000084226 sec CPU
average: 0.253643142 sec real / 0.000075407 sec CPU
stdev : 0.000641286 sec real / 0.000002025 sec CPU
local -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.355105000 sec real / 0.000056627 sec CPU
maximum: 0.391689000 sec real / 0.000080369 sec CPU
average: 0.357542464 sec real / 0.000074811 sec CPU
stdev : 0.003493931 sec real / 0.000002581 sec CPU
global
Strip out best and worst realtime result
minimum: 0.289823000 sec real / 0.000065591 sec CPU
maximum: 0.292342000 sec real / 0.000089039 sec CPU
average: 0.291038785 sec real / 0.000074941 sec CPU
stdev : 0.000540335 sec real / 0.000003253 sec CPU
global -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.422357000 sec real / 0.000056080 sec CPU
maximum: 0.430025000 sec real / 0.000092561 sec CPU
average: 0.424305678 sec real / 0.000076960 sec CPU
stdev : 0.000848422 sec real / 0.000003468 sec CPU
take2
local
Strip out best and worst realtime result
minimum: 0.244879000 sec real / 0.000062648 sec CPU
maximum: 0.249994000 sec real / 0.000088941 sec CPU
average: 0.246728928 sec real / 0.000071952 sec CPU
stdev : 0.000634173 sec real / 0.000003605 sec CPU
local -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.341390000 sec real / 0.000051786 sec CPU
maximum: 0.346805000 sec real / 0.000076650 sec CPU
average: 0.343283357 sec real / 0.000072815 sec CPU
stdev : 0.001045857 sec real / 0.000002876 sec CPU
global
Strip out best and worst realtime result
minimum: 0.280108000 sec real / 0.000064175 sec CPU
maximum: 0.288343000 sec real / 0.000086420 sec CPU
average: 0.281190142 sec real / 0.000073883 sec CPU
stdev : 0.000946847 sec real / 0.000002963 sec CPU
global -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.404168000 sec real / 0.000047867 sec CPU
maximum: 0.409607000 sec real / 0.000089063 sec CPU
average: 0.406042035 sec real / 0.000073105 sec CPU
stdev : 0.001200557 sec real / 0.000002313 sec CPU
take3
local
Strip out best and worst realtime result
minimum: 0.219594000 sec real / 0.000063193 sec CPU
maximum: 0.221967000 sec real / 0.000069838 sec CPU
average: 0.220638857 sec real / 0.000065311 sec CPU
stdev : 0.000659280 sec real / 0.000001556 sec CPU
local -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.292865000 sec real / 0.000052557 sec CPU
maximum: 0.297813000 sec real / 0.000088007 sec CPU
average: 0.294272428 sec real / 0.000073999 sec CPU
stdev : 0.000734011 sec real / 0.000003457 sec CPU
global
Strip out best and worst realtime result
minimum: 0.248331000 sec real / 0.000065781 sec CPU
maximum: 0.251560000 sec real / 0.000083441 sec CPU
average: 0.249498928 sec real / 0.000074084 sec CPU
stdev : 0.000521804 sec real / 0.000002443 sec CPU
global -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.344976000 sec real / 0.000050839 sec CPU
maximum: 0.350706000 sec real / 0.000086602 sec CPU
average: 0.346507607 sec real / 0.000073651 sec CPU
stdev : 0.001035954 sec real / 0.000003688 sec CPU
take4
local
Strip out best and worst realtime result
minimum: 0.199643000 sec real / 0.000063611 sec CPU
maximum: 0.207476000 sec real / 0.000072059 sec CPU
average: 0.201715642 sec real / 0.000065163 sec CPU
stdev : 0.002009911 sec real / 0.000001659 sec CPU
local -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.253969000 sec real / 0.000056606 sec CPU
maximum: 0.264754000 sec real / 0.000072700 sec CPU
average: 0.256445071 sec real / 0.000063609 sec CPU
stdev : 0.001690957 sec real / 0.000000905 sec CPU
global
Strip out best and worst realtime result
minimum: 0.222315000 sec real / 0.000063257 sec CPU
maximum: 0.231086000 sec real / 0.000078530 sec CPU
average: 0.223764642 sec real / 0.000065032 sec CPU
stdev : 0.000751210 sec real / 0.000000672 sec CPU
global -E LD_BIND_NOW=1
optarg="LD_BIND_NOW=1"
Strip out best and worst realtime result
minimum: 0.295561000 sec real / 0.000056096 sec CPU
maximum: 0.303293000 sec real / 0.000086572 sec CPU
average: 0.297082285 sec real / 0.000074283 sec CPU
stdev : 0.001047270 sec real / 0.000003516 sec CPU
[-- Attachment #6: statsy --]
[-- Type: text/plain, Size: 2638 bytes --]
/tmp/startup.odt (empty doc with:
sub Main
Shell("killall sleep")
end sub
as the Open event macro, Low macro security setting),
/tmp/a.sh contains:
#!/bin/sh
DISPLAY=localhost:0 oowriter /tmp/startup.odt > /dev/null 2>&1 &
sleep 1200
and modified timing.c, such that it waits for user input
from stdin after every invocation is measured. unprelinked
numbers are each from ./timing.modified -c 10 -n /tmp/a.sh,
prelinked from ./timing.modified -c 20 -n /tmp/a.sh.
unprelinked
.hash
minimum: 1.715100000 sec real / 0.000051953 sec CPU
maximum: 1.774593000 sec real / 0.000058803 sec CPU
average: 1.731386200 sec real / 0.000054716 sec CPU
stdev : 0.016703570 sec real / 0.000002011 sec CPU
take1
minimum: 1.336888000 sec real / 0.000052909 sec CPU
maximum: 1.376870000 sec real / 0.000062253 sec CPU
average: 1.348290500 sec real / 0.000056337 sec CPU
stdev : 0.011036217 sec real / 0.000002695 sec CPU
take2
minimum: 1.306500000 sec real / 0.000052635 sec CPU
maximum: 1.327990000 sec real / 0.000060805 sec CPU
average: 1.316566200 sec real / 0.000056985 sec CPU
stdev : 0.007522361 sec real / 0.000002221 sec CPU
take3
minimum: 1.229256000 sec real / 0.000051459 sec CPU
maximum: 1.330513000 sec real / 0.000057706 sec CPU
average: 1.285629900 sec real / 0.000055250 sec CPU
stdev : 0.026779805 sec real / 0.000001934 sec CPU
take4
minimum: 1.120778000 sec real / 0.000054010 sec CPU
maximum: 1.296930000 sec real / 0.000062093 sec CPU
average: 1.195947600 sec real / 0.000057423 sec CPU
stdev : 0.048721391 sec real / 0.000002233 sec CPU
prelinked
.hash
minimum: 1.338352000 sec real / 0.000050213 sec CPU
maximum: 1.358660000 sec real / 0.000059908 sec CPU
average: 1.348639650 sec real / 0.000055596 sec CPU
stdev : 0.005795022 sec real / 0.000002687 sec CPU
take1
minimum: 1.097255000 sec real / 0.000054104 sec CPU
maximum: 1.204971000 sec real / 0.000061802 sec CPU
average: 1.160938850 sec real / 0.000056718 sec CPU
stdev : 0.040502782 sec real / 0.000002018 sec CPU
take2
minimum: 1.078807000 sec real / 0.000053083 sec CPU
maximum: 1.181643000 sec real / 0.000063952 sec CPU
average: 1.147430150 sec real / 0.000056455 sec CPU
stdev : 0.034557199 sec real / 0.000002833 sec CPU
take3
minimum: 1.056688000 sec real / 0.000046743 sec CPU
maximum: 1.161373000 sec real / 0.000070731 sec CPU
average: 1.133688450 sec real / 0.000057349 sec CPU
stdev : 0.027867890 sec real / 0.000004267 sec CPU
take4
minimum: 1.024210000 sec real / 0.000053391 sec CPU
maximum: 1.143304000 sec real / 0.000061477 sec CPU
average: 1.099958300 sec real / 0.000056757 sec CPU
stdev : 0.031722271 sec real / 0.000002175 sec CPU
next prev parent reply other threads:[~2006-07-07 14:45 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <44A9D4EB.2040107@redhat.com>
[not found] ` <BAY22-F13B0B8E34EA055F9BF6E50C7710@phx.gbl>
[not found] ` <20060705090438.GJ3823@sunsite.mff.cuni.cz>
2006-07-06 11:26 ` DT_GNU_HASH benchmark results Jakub Jelinek
2006-07-06 18:22 ` DT_GNU_HASH latest patches Jakub Jelinek
2006-07-06 19:53 ` djamel anonymous
2006-07-07 14:45 ` Jakub Jelinek [this message]
2006-07-07 15:57 ` djamel anonymous
2006-07-09 22:27 ` Jakub Jelinek
2006-07-08 2:45 ` Eric Christopher
2006-07-09 22:35 ` Jakub Jelinek
2006-07-10 14:18 ` Nick Clifton
2006-07-10 14:18 ` Nick Clifton
2006-07-10 14:20 ` Nick Clifton
2006-07-10 21:52 ` Jakub Jelinek
2006-07-11 13:35 ` Hans-Peter Nilsson
2006-07-11 13:58 ` Jakub Jelinek
2006-07-07 10:07 ` Michael Meeks
2006-07-07 13:43 ` Ulrich Drepper
2006-07-07 13:49 ` Jakub Jelinek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060707144406.GO3823@sunsite.mff.cuni.cz \
--to=jakub@redhat.com \
--cc=binutils@sources.redhat.com \
--cc=djam8193ah@hotmail.com \
--cc=drepper@redhat.com \
--cc=libc-alpha@sources.redhat.com \
--cc=michael.meeks@novell.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).