On Mon, May 2, 2011 at 4:16 PM, Jan Hubicka <hubi...@ucw.cz> wrote:
> 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;

If you skip node_map you can end up with false entries for re-used
trees.  So I don't think that's a good idea.

Richard.

>
>    /* The nodes pickled so far.  */
>    VEC(tree,heap) *nodes;
>

Reply via email to