<p dir="ltr"><br>
18. okt. 2016 00.07 skrev "Jan Ziak" <<a href="mailto:0xe2.0x9a.0x9b@gmail.com">0xe2.0x9a.0x9b@gmail.com</a>>:<br>
><br>
> This patch replaces the ir_variable_refcount_entry's linked-list<br>
> with an array-list.<br>
><br>
> The array-list has local storage which does not require ANY additional<br>
> allocations if the list has small number of elements. The size of this<br>
> storage is configurable for each variable.<br>
><br>
> Benchmark results for "./run -1 shaders" from shader-db[1]:<br>
><br>
> - The total number of executed instructions goes down from 64.184 to 63.797<br>
>   giga-instructions when Mesa is compiled with "gcc -O0 ..."<br>
> - In the call tree starting at function do_dead_code():<br>
>   - the number of calls to malloc() is reduced by about 10%<br>
>   - the number of calls to free() is reduced by about 30%<br>
><br>
> [1] git://<a href="http://anongit.freedesktop.org/mesa/shader-db">anongit.freedesktop.org/mesa/shader-db</a></p>
<p dir="ltr">Nice find. I would not be surprised if there are more cases of<br>
inappropriate data structures being used, causing overhead.<br>
I can't quite tell, as Gmail tends to mangle whitespace stuff,<br>
but it looks like there might be some style issues with<br>
not everything following the three-space indent, no tabs<br>
policy that mesa tries to stick to.</p>
<p dir="ltr">On the subject of this patch, some thoughts that came to mind:<br>
I think it would be preferred if the implementation was in C.<br>
Using this in NIR, which tries to be C only, might be a possibility?<br>
I also seem to recall that I reviewed some patches that<br>
Jason wrote back a good while ago for NIR that implemented a<br>
dynamically resizing array of sorts that might be of interest.</p>
<p dir="ltr">Just some random thoughts.<br>
-Thomas</p>
<p dir="ltr">><br>
> Signed-off-by: Jan Ziak (<a href="http://atom-symbol.net">http://atom-symbol.net</a>) <<a href="mailto:0xe2.0x9a.0x9b@gmail.com">0xe2.0x9a.0x9b@gmail.com</a>><br>
> ---<br>
>  src/compiler/glsl/ir_variable_refcount.cpp |  14 +--<br>
>  src/compiler/glsl/ir_variable_refcount.h   |   8 +-<br>
>  src/compiler/glsl/opt_dead_code.cpp        |  19 ++--<br>
>  src/util/fast_list.h                       | 167 +++++++++++++++++++++++++++++<br>
>  4 files changed, 176 insertions(+), 32 deletions(-)<br>
><br>
> diff --git a/src/compiler/glsl/ir_variable_refcount.cpp b/src/compiler/glsl/ir_variable_refcount.cpp<br>
> index 8306be1..94d6edc 100644<br>
> --- a/src/compiler/glsl/ir_variable_refcount.cpp<br>
> +++ b/src/compiler/glsl/ir_variable_refcount.cpp<br>
> @@ -46,15 +46,6 @@ static void<br>
>  free_entry(struct hash_entry *entry)<br>
>  {<br>
>     ir_variable_refcount_entry *ivre = (ir_variable_refcount_entry *) entry->data;<br>
> -<br>
> -   /* Free assignment list */<br>
> -   exec_node *n;<br>
> -   while ((n = ivre->assign_list.pop_head()) != NULL) {<br>
> -      struct assignment_entry *assignment_entry =<br>
> -         exec_node_data(struct assignment_entry, n, link);<br>
> -      free(assignment_entry);<br>
> -   }<br>
> -<br>
>     delete ivre;<br>
>  }<br>
><br>
> @@ -142,10 +133,7 @@ ir_variable_refcount_visitor::visit_leave(ir_assignment *ir)<br>
>         */<br>
>        assert(entry->referenced_count >= entry->assigned_count);<br>
>        if (entry->referenced_count == entry->assigned_count) {<br>
> -         struct assignment_entry *assignment_entry =<br>
> -            (struct assignment_entry *)calloc(1, sizeof(*assignment_entry));<br>
> -         assignment_entry->assign = ir;<br>
> -         entry->assign_list.push_head(&assignment_entry->link);<br>
> +         entry->assign_list.add(ir);<br>
>        }<br>
>     }<br>
><br>
> diff --git a/src/compiler/glsl/ir_variable_refcount.h b/src/compiler/glsl/ir_variable_refcount.h<br>
> index 08a11c0..c3ec5fe 100644<br>
> --- a/src/compiler/glsl/ir_variable_refcount.h<br>
> +++ b/src/compiler/glsl/ir_variable_refcount.h<br>
> @@ -32,11 +32,7 @@<br>
>  #include "ir.h"<br>
>  #include "ir_visitor.h"<br>
>  #include "compiler/glsl_types.h"<br>
> -<br>
> -struct assignment_entry {<br>
> -   exec_node link;<br>
> -   ir_assignment *assign;<br>
> -};<br>
> +#include "util/fast_list.h"<br>
><br>
>  class ir_variable_refcount_entry<br>
>  {<br>
> @@ -50,7 +46,7 @@ public:<br>
>      * This is intended to be used for dead code optimisation and may<br>
>      * not be a complete list.<br>
>      */<br>
> -   exec_list assign_list;<br>
> +   arraylist<ir_assignment*,4> assign_list;<br>
><br>
>     /** Number of times the variable is referenced, including assignments. */<br>
>     unsigned referenced_count;<br>
> diff --git a/src/compiler/glsl/opt_dead_code.cpp b/src/compiler/glsl/opt_dead_code.cpp<br>
> index 75e668a..06e8c3d 100644<br>
> --- a/src/compiler/glsl/opt_dead_code.cpp<br>
> +++ b/src/compiler/glsl/opt_dead_code.cpp<br>
> @@ -52,7 +52,7 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)<br>
><br>
>     struct hash_entry *e;<br>
>     hash_table_foreach(<a href="http://v.ht">v.ht</a>, e) {<br>
> -      ir_variable_refcount_entry *entry = (ir_variable_refcount_entry *)e->data;<br>
> +      ir_variable_refcount_entry *const entry = (ir_variable_refcount_entry *)e->data;<br>
><br>
>        /* Since each assignment is a reference, the refereneced count must be<br>
>         * greater than or equal to the assignment count.  If they are equal,<br>
> @@ -89,7 +89,7 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)<br>
>        if (entry->var->data.always_active_io)<br>
>           continue;<br>
><br>
> -      if (!entry->assign_list.is_empty()) {<br>
> +      if (!entry->assign_list.empty()) {<br>
>          /* Remove all the dead assignments to the variable we found.<br>
>           * Don't do so if it's a shader or function output, though.<br>
>           */<br>
> @@ -98,26 +98,19 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)<br>
>               entry->var->data.mode != ir_var_shader_out &&<br>
>               entry->var->data.mode != ir_var_shader_storage) {<br>
><br>
> -            while (!entry->assign_list.is_empty()) {<br>
> -               struct assignment_entry *assignment_entry =<br>
> -                  exec_node_data(struct assignment_entry,<br>
> -                                 entry->assign_list.get_head_raw(), link);<br>
> -<br>
> -              assignment_entry->assign->remove();<br>
> -<br>
> +            for(ir_assignment *assign : entry->assign_list) {<br>
> +              assign->remove();<br>
>                if (debug) {<br>
>                   printf("Removed assignment to %s@%p\n",<br>
>                          entry->var->name, (void *) entry->var);<br>
>                 }<br>
> -<br>
> -               assignment_entry->link.remove();<br>
> -               free(assignment_entry);<br>
>              }<br>
> +            entry->assign_list.clear();<br>
>              progress = true;<br>
>          }<br>
>        }<br>
><br>
> -      if (entry->assign_list.is_empty()) {<br>
> +      if (entry->assign_list.empty()) {<br>
>          /* If there are no assignments or references to the variable left,<br>
>           * then we can remove its declaration.<br>
>           */<br>
> diff --git a/src/util/fast_list.h b/src/util/fast_list.h<br>
> new file mode 100644<br>
> index 0000000..4abd965<br>
> --- /dev/null<br>
> +++ b/src/util/fast_list.h<br>
> @@ -0,0 +1,167 @@<br>
> +/*<br>
> + * Copyright © 2016 Jan Ziak<br>
> + *<br>
> + * Permission is hereby granted, free of charge, to any person obtaining a<br>
> + * copy of this software and associated documentation files (the "Software"),<br>
> + * to deal in the Software without restriction, including without limitation<br>
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
> + * and/or sell copies of the Software, and to permit persons to whom the<br>
> + * Software is furnished to do so, subject to the following conditions:<br>
> + *<br>
> + * The above copyright notice and this permission notice (including the next<br>
> + * paragraph) shall be included in all copies or substantial portions of the<br>
> + * Software.<br>
> + *<br>
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
> + * IN THE SOFTWARE.<br>
> + *<br>
> + * Authors:<br>
> + *    Jan Ziak (<a href="http://atom-symbol.net">http://atom-symbol.net</a>) <<a href="mailto:0xe2.0x9x.0a9b@gmail.com">0xe2.0x9x.0a9b@gmail.com</a>><br>
> + */<br>
> +<br>
> +/**<br>
> + * @file fast_list.h<br>
> + *<br>
> + * High-performance C++ list implementation.<br>
> + */<br>
> +<br>
> +#ifndef _UTIL_FAST_LIST_H<br>
> +#define _UTIL_FAST_LIST_H<br>
> +<br>
> +#include <new><br>
> +#include <stdlib.h><br>
> +#include <string.h><br>
> +<br>
> +/**<br>
> + * A high-performance array list.<br>
> + *<br>
> + * The list doesn't support elements whose behavior depends on the memory address of the element.<br>
> + *<br>
> + * @param T  List element type.<br>
> + *<br>
> + * @param N  The number of statically allocated elements to achieve the highest overall performance.<br>
> + *           N is typically 0, 2, 4 or 8 depending on the runtime usage pattern of a particular list<br>
> + *           variable in the source code.<br>
> + */<br>
> +template<typename T, size_t N><br>
> +struct arraylist<br>
> +{<br>
> +   size_t len;  // Length<br>
> +   size_t cap;  // Capacity (size of memory allocated to 'elem')<br>
> +   T *elem;     // List elements<br>
> +   uint8_t local[N*sizeof(T)];  // Fast local preallocated storage for lists with length 0..N<br>
> +<br>
> +   arraylist() {<br>
> +      len = 0;<br>
> +      cap = N;<br>
> +      elem = (N ? (T*)local : NULL);<br>
> +   }<br>
> +<br>
> +   ~arraylist() {<br>
> +      if(!__has_trivial_destructor(T)) {<br>
> +         for(size_t i=0; i<len; i++) {<br>
> +            elem[i].~T();<br>
> +         }<br>
> +      }<br>
> +      if((N && elem != (T*)local) && elem) {<br>
> +         free(elem);<br>
> +      }<br>
> +   }<br>
> +<br>
> +   arraylist(const arraylist<T,N> &a) = delete;<br>
> +   void operator=(const arraylist<T,N> &a) = delete;<br>
> +<br>
> +   bool empty() const {<br>
> +      return len==0;<br>
> +   }<br>
> +<br>
> +   void clear() {<br>
> +      if(!__has_trivial_destructor(T)) {<br>
> +         for(size_t i=0; i<len; i++) {<br>
> +            elem[i].~T();<br>
> +         }<br>
> +      }<br>
> +      len = 0;<br>
> +   }<br>
> +<br>
> +   arraylist<T,N>& add(const T &e) {<br>
> +      if(len == cap) {<br>
> +         enlarge1();<br>
> +      }<br>
> +      new (&elem[len++]) T(e);<br>
> +      return *this;<br>
> +   }<br>
> +<br>
> +   T& operator[](size_t i) { return elem[i]; }<br>
> +   const T& operator[](size_t i) const { return elem[i]; }<br>
> +<br>
> +   /*<br>
> +    * C++ iterators:<br>
> +    */<br>
> +<br>
> +   struct const_iterator_t {<br>
> +      const T *const elem;<br>
> +      size_t i;<br>
> +      const_iterator_t(const T *_elem, size_t _i) : elem(_elem), i(_i) {}<br>
> +      const T& operator*() const { return elem[i]; }<br>
> +      void operator++() { i++; }<br>
> +      bool operator!=(const const_iterator_t &b) const { return i < b.i; }<br>
> +   };<br>
> +   struct iterator_t {<br>
> +      T *const elem;<br>
> +      size_t i;<br>
> +      iterator_t(T *_elem, size_t _i) : elem(_elem), i(_i) {}<br>
> +      T& operator*() const { return elem[i]; }<br>
> +      void operator++() { i++; }<br>
> +      bool operator!=(const iterator_t &b) const { return i < b.i; }<br>
> +   };<br>
> +<br>
> +   const_iterator_t const_begin() const { return const_iterator_t(elem, 0); }<br>
> +   const_iterator_t const_end() const { return const_iterator_t(elem, len); }<br>
> +<br>
> +   const_iterator_t begin() const { return const_iterator_t(elem, 0); }<br>
> +   const_iterator_t end() const { return const_iterator_t(elem, len); }<br>
> +<br>
> +   iterator_t begin() { return iterator_t(elem, 0); }<br>
> +   iterator_t end() { return iterator_t(elem, len); }<br>
> +<br>
> +   /*<br>
> +    * Methods for std::vector<T> compatibility:<br>
> +    */<br>
> +<br>
> +   arraylist<T,N>& push_back(const T &e) { return add(e); }<br>
> +<br>
> +private:<br>
> +   void enlarge1() {<br>
> +      if(N) {<br>
> +         cap *= 2;<br>
> +         if(elem == (T*)local) {<br>
> +            elem = (T*)malloc(cap*sizeof(T));<br>
> +            if(!elem) {<br>
> +               abort();<br>
> +            }<br>
> +            memcpy(elem, local, len*sizeof(T));<br>
> +         }<br>
> +         else {<br>
> +            elem = (T*)realloc(elem, cap*sizeof(T));<br>
> +            if(!elem) {<br>
> +               abort();<br>
> +            }<br>
> +         }<br>
> +      }<br>
> +      else {<br>
> +         cap = (cap ? 2*cap : 4);<br>
> +         elem = (T*)realloc(elem, cap*sizeof(T));<br>
> +         if(!elem) {<br>
> +            abort();<br>
> +         }<br>
> +      }<br>
> +   }<br>
> +};<br>
> +<br>
> +#endif /* _UTIL_FAST_LIST_H */<br>
> \ No newline at end of file<br>
> _______________________________________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</p>