Hi, according to oprofile, libiberty hashing takes about 30% of streaming in time and according to callgrind, the most busy cache is node_map cache in the streamer.
This patch turns it into pointer-map that also saves about 400MB of memory and is bit prettier. I get about 8-10% speedup on Mozilla streaming. There are other uses of tree_int map, I could probably convert them, too. Bootstrapped/regtested x86_64-linux, OK? Honza * lto-streamer.c (lto_streamer_cache_insert_1, lto_streamer_cache_lookup, lto_streamer_cache_create, lto_streamer_cache_delete): Use pointer map instead of hashtable. * lto-streamer.h (lto_streamer_cache_d): Turn node_map into pointer_map. Index: lto-streamer.c =================================================================== *** lto-streamer.c (revision 173251) --- lto-streamer.c (working copy) *************** lto_streamer_cache_insert_1 (struct lto_ *** 348,373 **** bool insert_at_next_slot_p) { void **slot; - struct tree_int_map d_entry, *entry; unsigned ix; bool existed_p; gcc_assert (t); ! d_entry.base.from = t; ! slot = htab_find_slot (cache->node_map, &d_entry, INSERT); ! if (*slot == NULL) { /* Determine the next slot to use in the cache. */ if (insert_at_next_slot_p) ix = VEC_length (tree, cache->nodes); else ix = *ix_p; ! ! entry = (struct tree_int_map *)pool_alloc (cache->node_map_entries); ! entry->base.from = t; ! entry->to = ix; ! *slot = entry; lto_streamer_cache_add_to_node_array (cache, ix, t); --- 348,367 ---- bool insert_at_next_slot_p) { void **slot; unsigned ix; bool existed_p; gcc_assert (t); ! slot = pointer_map_insert (cache->node_map, t); ! if (!*slot) { /* Determine the next slot to use in the cache. */ if (insert_at_next_slot_p) ix = VEC_length (tree, cache->nodes); else ix = *ix_p; ! *slot = (void *)(size_t) (ix); lto_streamer_cache_add_to_node_array (cache, ix, t); *************** lto_streamer_cache_insert_1 (struct lto_ *** 376,383 **** } else { ! entry = (struct tree_int_map *) *slot; ! ix = entry->to; if (!insert_at_next_slot_p && ix != *ix_p) { --- 370,376 ---- } else { ! ix = (size_t) *slot; if (!insert_at_next_slot_p && ix != *ix_p) { *************** lto_streamer_cache_lookup (struct lto_st *** 442,455 **** unsigned *ix_p) { void **slot; - struct tree_int_map d_slot; bool retval; unsigned ix; gcc_assert (t); ! d_slot.base.from = t; ! slot = htab_find_slot (cache->node_map, &d_slot, NO_INSERT); if (slot == NULL) { retval = false; --- 435,446 ---- unsigned *ix_p) { void **slot; bool retval; unsigned ix; gcc_assert (t); ! slot = pointer_map_contains (cache->node_map, t); if (slot == NULL) { retval = false; *************** lto_streamer_cache_lookup (struct lto_st *** 458,464 **** else { retval = true; ! ix = ((struct tree_int_map *) *slot)->to; } if (ix_p) --- 449,455 ---- else { retval = true; ! ix = (size_t) *slot; } if (ix_p) *************** lto_streamer_cache_create (void) *** 608,618 **** cache = XCNEW (struct lto_streamer_cache_d); ! cache->node_map = htab_create (101, tree_int_map_hash, tree_int_map_eq, NULL); ! ! cache->node_map_entries = create_alloc_pool ("node map", ! sizeof (struct tree_int_map), ! 100); /* Load all the well-known tree nodes that are always created by the compiler on startup. This prevents writing them out --- 599,605 ---- cache = XCNEW (struct lto_streamer_cache_d); ! cache->node_map = pointer_map_create (); /* Load all the well-known tree nodes that are always created by the compiler on startup. This prevents writing them out *************** lto_streamer_cache_delete (struct lto_st *** 636,643 **** if (c == NULL) return; ! htab_delete (c->node_map); ! free_alloc_pool (c->node_map_entries); VEC_free (tree, heap, c->nodes); free (c); } --- 623,629 ---- if (c == NULL) return; ! pointer_map_destroy (c->node_map); VEC_free (tree, heap, c->nodes); free (c); } Index: lto-streamer.h =================================================================== *** lto-streamer.h (revision 173251) --- lto-streamer.h (working copy) *************** typedef void (lto_free_section_data_f) ( *** 346,355 **** struct lto_streamer_cache_d { /* The mapping between tree nodes and slots into the nodes array. */ ! htab_t node_map; ! ! /* Node map to store entries into. */ ! alloc_pool node_map_entries; /* The nodes pickled so far. */ VEC(tree,heap) *nodes; --- 346,352 ---- struct lto_streamer_cache_d { /* The mapping between tree nodes and slots into the nodes array. */ ! struct pointer_map_t GTY((skip)) *node_map; /* The nodes pickled so far. */ VEC(tree,heap) *nodes;