[Mesa-dev] [RFC 1/2] glsl: Use hash tables for opt_constant_propagation() acp sets.

Rhys Kidd rhyskidd at gmail.com
Wed Oct 7 01:54:59 PDT 2015


On 7 October 2015 at 04:00, Kenneth Graunke <kenneth at whitecape.org> wrote:

> On Sunday, September 20, 2015 07:54:56 PM Rhys Kidd wrote:
> > ---
> >  src/glsl/opt_constant_propagation.cpp | 63
> +++++++++++++++++++++--------------
> >  1 file changed, 38 insertions(+), 25 deletions(-)
>
> Hi Rhys!
>
> Thanks for looking into this :)  A couple of comments...
>
> Now that acp_entry isn't used in any lists, you can make it stop
> inheriting from exec_node, which will remove the prev/next pointers.
>
> Do you have any data on whether this speeds up compile times at all?
> I was just running 'time glslparsertest' (or 'time shader_runner') on
> the shader from [ https://bugs.freedesktop.org/show_bug.cgi?id=91857 ].
> It should be pretty easy to measure (earlier patches shaved whole
> seconds off the compile time); it'd be nice to include that in the
> commit message.
>
> > diff --git a/src/glsl/opt_constant_propagation.cpp
> b/src/glsl/opt_constant_propagation.cpp
> > index 184aaa1..b6cbf61 100644
> > --- a/src/glsl/opt_constant_propagation.cpp
> > +++ b/src/glsl/opt_constant_propagation.cpp
> > @@ -95,7 +95,8 @@ public:
> >        progress = false;
> >        killed_all = false;
> >        mem_ctx = ralloc_context(0);
> > -      this->acp = new(mem_ctx) exec_list;
> > +      this->acp = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> > +                                          _mesa_key_pointer_equal);
> >        this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> >                                              _mesa_key_pointer_equal);
> >     }
> > @@ -118,8 +119,8 @@ public:
> >     void handle_if_block(exec_list *instructions);
> >     void handle_rvalue(ir_rvalue **rvalue);
> >
> > -   /** List of acp_entry: The available constants to propagate */
> > -   exec_list *acp;
> > +   /** Hash table of acp_entry: The available constants to propagate */
> > +   hash_table *acp;
> >
> >     /**
> >      * List of kill_entry: The masks of variables whose values were
> > @@ -206,11 +207,13 @@
> ir_constant_propagation_visitor::constant_propagation(ir_rvalue **rvalue) {
> >        channel = i;
> >        }
> >
> > -      foreach_in_list(acp_entry, entry, this->acp) {
> > -      if (entry->var == deref->var && entry->write_mask & (1 <<
> channel)) {
> > +      hash_entry *acp_hash_entry;
> > +      hash_table_foreach(this->acp, acp_hash_entry) {
> > +         acp_entry *entry = (acp_entry *) acp_hash_entry->data;
> > +         if (entry->var == deref->var && entry->write_mask & (1 <<
> channel)) {
> >           found = entry;
> >           break;
> > -      }
> > +         }
>
> This seems a bit strange...here, we're still walking over the entire
> hash table, manually checking if each entry's var matches.  In fact, I
> don't see any calls to _mesa_hash_table_search in this patch.
>
> The point of using a hash table is that it provides constant-time / O(1)
> lookups of data, compared to a linked list's linear-time / O(n) lookups.
> Generally, hash tables have a bit more overhead than a linked list...so
> if we're not gaining constant time lookup, I'm not sure it's worth it.
>
> Perhaps we need to include the write mask in the key somehow?  Or, hash
> on variable, but instead of a single entry, get a list of entries back?
>
> >        }
> >
> >        if (!found)
> > @@ -264,11 +267,12 @@
> ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
> >      * block.  Any instructions at global scope will be shuffled into
> >      * main() at link time, so they're irrelevant to us.
> >      */
> > -   exec_list *orig_acp = this->acp;
> > +   hash_table *orig_acp = this->acp;
> >     hash_table *orig_kills = this->kills;
> >     bool orig_killed_all = this->killed_all;
> >
> > -   this->acp = new(mem_ctx) exec_list;
> > +   this->acp = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> > +                                       _mesa_key_pointer_equal);
> >     this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> >                                           _mesa_key_pointer_equal);
> >     this->killed_all = false;
> > @@ -345,7 +349,8 @@ ir_constant_propagation_visitor::visit_enter(ir_call
> *ir)
> >     /* Since we're unlinked, we don't (necssarily) know the side effects
> of
> >      * this call.  So kill all copies.
> >      */
> > -   acp->make_empty();
> > +   acp = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> > +                                 _mesa_key_pointer_equal);
> >     this->killed_all = true;
> >
> >     return visit_continue_with_parent;
> > @@ -354,24 +359,29 @@
> ir_constant_propagation_visitor::visit_enter(ir_call *ir)
> >  void
> >  ir_constant_propagation_visitor::handle_if_block(exec_list
> *instructions)
> >  {
> > -   exec_list *orig_acp = this->acp;
> > +   hash_table *orig_acp = this->acp;
> >     hash_table *orig_kills = this->kills;
> >     bool orig_killed_all = this->killed_all;
> >
> > -   this->acp = new(mem_ctx) exec_list;
> > +   this->acp = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> > +                                       _mesa_key_pointer_equal);
> >     this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
> >                                           _mesa_key_pointer_equal);
> >     this->killed_all = false;
> >
> >     /* Populate the initial acp with a constant of the original */
> > -   foreach_in_list(acp_entry, a, orig_acp) {
> > -      this->acp->push_tail(new(this->mem_ctx) acp_entry(a));
> > +   hash_entry *htk;
> > +   hash_table_foreach(orig_acp, htk) {
> > +      acp_entry *a = (acp_entry *) htk->data;
> > +      _mesa_hash_table_insert(this->acp, a,
> > +                              new(this->mem_ctx) acp_entry(a));
>
> You might consider doing:
>
>    _mesa_hash_table_insert_pre_hashed(this->acp, htk->hash, a,
>                                       new(mem_ctx) acp_entry(a));
>
> This avoids having to re-hash every entry in the table when creating a
> new hash table.  Since both tables use the same hash function, and the
> same key, you may as well use the value you already have.
>
> I do wonder if it would make sense to add a _mesa_hash_table_copy()
> function that memcpy's the contents...since that would be even cheaper
> still...but here you're actually inserting a new copy of acp_entry, so
> I guess that wouldn't work.
>
> We might be able to get away with not copying the ACP entry...one reason
> for doing so was because it contained prev/next pointers, and so could
> only be present in one linked list at a time.  Now that we're using hash
> tables, we don't have that restriction.  However, it looks like kill()
> actually modifies ACP entries, so it's probably easier to continue
> copying them for now.
>

Hello Kenneth,

Thank you for your feedback. I'll review and then resubmit a v2 patchset
addressing these comments.

Regards,
Rhys
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20151007/75c3d997/attachment.html>


More information about the mesa-dev mailing list