<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>