[Mesa-dev] [PATCH 18/18] mesa: overhaul debug namespace support

Chia-I Wu olvaffe at gmail.com
Fri Apr 25 15:09:50 PDT 2014


On Fri, Apr 25, 2014 at 10:30 PM, Brian Paul <brianp at vmware.com> wrote:
> On 04/25/2014 04:42 AM, Chia-I Wu wrote:
>>
>> _mesa_HashTable is not well-suited for us: it locks a mutex unnecessarily
>> and
>> it does not accept 0 as the key (and have branches to handle 1 specially).
>> What we really need is a sparse array.  Whether it should be implemented
>> as a
>> hash table, a list, or a bsearch()-able array requires investigations of
>> the
>> use models.
>>
>> We choose to implement it as a list for now, assuming it is common to have
>> a
>> short list of IDs in each (source, type) namespace.  The code is simpler,
>> and
>> the memory footprint is lower.  This also fixes several corner cases such
>> as
>> making messages to have different states at different severities.
>>
>> Signed-off-by: Chia-I Wu <olv at lunarg.com>
>> ---
>>   src/mesa/main/errors.c | 264
>> ++++++++++++++++---------------------------------
>>   1 file changed, 86 insertions(+), 178 deletions(-)
>>
>> diff --git a/src/mesa/main/errors.c b/src/mesa/main/errors.c
>> index 8ef19d2..8a857ec 100644
>> --- a/src/mesa/main/errors.c
>> +++ b/src/mesa/main/errors.c
>> @@ -41,20 +41,20 @@
>>   static mtx_t DynamicIDMutex = _MTX_INITIALIZER_NP;
>>   static GLuint NextDynamicID = 1;
>>
>> -struct gl_debug_severity
>> +/**
>> + * A namespace element.
>> + */
>> +struct gl_debug_element
>>   {
>>      struct simple_node link;
>>      GLuint ID;
>> +   uint32_t State;
>
>
> Looks like State and DefaultState below could be GLbitfield, right?
Right.  I forgot GLbitfield's existence.  I will also add a comment.
> Alternately, a comment on those fields indicating that they're bitfields
> (and what the bits are) would be helpful.
>
> -Brian
>
>
>
>>   };
>>
>>   struct gl_debug_namespace
>>   {
>> -   struct _mesa_HashTable *IDs;
>> -   unsigned ZeroID; /* a HashTable won't take zero, so store its state
>> here */
>> -   /** lists of IDs in the hash table at each severity */
>> -   struct simple_node Severity[MESA_DEBUG_SEVERITY_COUNT];
>> -
>> -   GLboolean Defaults[MESA_DEBUG_SEVERITY_COUNT];
>> +   struct simple_node Elements;
>> +   uint32_t DefaultState;
>>   };
>>
>>   struct gl_debug_group {
>> @@ -190,48 +190,6 @@ debug_get_id(GLuint *id)
>>      }
>>   }
>>
>> -
>> -/*
>> - * We store a bitfield in the hash table, with five possible values
>> total.
>> - *
>> - * The ENABLED_BIT's purpose is self-explanatory.
>> - *
>> - * The FOUND_BIT is needed to differentiate the value of DISABLED from
>> - * the value returned by HashTableLookup() when it can't find the given
>> key.
>> - *
>> - * The KNOWN_SEVERITY bit is a bit complicated:
>> - *
>> - * A client may call Control() with an array of IDs, then call Control()
>> - * on all message IDs of a certain severity, then Insert() one of the
>> - * previously specified IDs, giving us a known severity level, then call
>> - * Control() on all message IDs of a certain severity level again.
>> - *
>> - * After the first call, those IDs will have a FOUND_BIT, but will not
>> - * exist in any severity-specific list, so the second call will not
>> - * impact them. This is undesirable but unavoidable given the API:
>> - * The only entrypoint that gives a severity for a client-defined ID
>> - * is the Insert() call.
>> - *
>> - * For the sake of Control(), we want to maintain the invariant
>> - * that an ID will either appear in none of the three severity lists,
>> - * or appear once, to minimize pointless duplication and potential
>> surprises.
>> - *
>> - * Because Insert() is the only place that will learn an ID's severity,
>> - * it should insert an ID into the appropriate list, but only if the ID
>> - * doesn't exist in it or any other list yet. Because searching all three
>> - * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
>> - */
>> -enum {
>> -   FOUND_BIT = 1 << 0,
>> -   ENABLED_BIT = 1 << 1,
>> -   KNOWN_SEVERITY = 1 << 2,
>> -
>> -   /* HashTable reserves zero as a return value meaning 'not found' */
>> -   NOT_FOUND = 0,
>> -   DISABLED = FOUND_BIT,
>> -   ENABLED = ENABLED_BIT | FOUND_BIT
>> -};
>> -
>>   static void
>>   debug_message_clear(struct gl_debug_message *msg)
>>   {
>> @@ -277,84 +235,45 @@ debug_message_store(struct gl_debug_message *msg,
>>   static void
>>   debug_namespace_init(struct gl_debug_namespace *ns)
>>   {
>> -   int sev;
>> -
>> -   memset(ns, 0, sizeof(*ns));
>> -
>> -   ns->IDs = _mesa_NewHashTable();
>> -   assert(ns->IDs);
>> -
>> -   for (sev = 0; sev < Elements(ns->Severity); sev++)
>> -      make_empty_list(&ns->Severity[sev]);
>> +   make_empty_list(&ns->Elements);
>>
>>      /* Enable all the messages with severity HIGH or MEDIUM by default */
>> -   ns->Defaults[MESA_DEBUG_SEVERITY_HIGH] = GL_TRUE;
>> -   ns->Defaults[MESA_DEBUG_SEVERITY_MEDIUM] = GL_TRUE;
>> -}
>> -
>> -static void
>> -debug_namespace_clear_cb(GLuint key, void *data, void *userData)
>> -{
>> +   ns->DefaultState = (1 << MESA_DEBUG_SEVERITY_HIGH) |
>> +                      (1 << MESA_DEBUG_SEVERITY_MEDIUM);
>>   }
>>
>>   static void
>>   debug_namespace_clear(struct gl_debug_namespace *ns)
>>   {
>> -   int sev;
>> -
>> -   _mesa_HashDeleteAll(ns->IDs, debug_namespace_clear_cb, NULL);
>> -   _mesa_DeleteHashTable(ns->IDs);
>> +   struct simple_node *node, *tmp;
>>
>> -   for (sev = 0; sev < Elements(ns->Severity); sev++) {
>> -      struct simple_node *node, *tmp;
>> -
>> -      foreach_s(node, tmp, &ns->Severity[sev])
>> -         free(node);
>> -   }
>> +   foreach_s(node, tmp, &ns->Elements)
>> +      free(node);
>>   }
>>
>>   static bool
>>   debug_namespace_copy(struct gl_debug_namespace *dst,
>>                        const struct gl_debug_namespace *src)
>>   {
>> -   bool err = false;
>> -   int sev;
>> -
>> -   /* copy id settings */
>> -   dst->IDs = _mesa_HashClone(src->IDs);
>> -   if (!dst->IDs)
>> -      return false;
>> +   struct simple_node *node;
>>
>> -   for (sev = 0; sev < Elements(dst->Severity); sev++) {
>> -      struct simple_node *node;
>> +   dst->DefaultState = src->DefaultState;
>>
>> -      /* copy default settings for unknown ids */
>> -      dst->Defaults[sev] = src->Defaults[sev];
>> +   make_empty_list(&dst->Elements);
>> +   foreach(node, &src->Elements) {
>> +      const struct gl_debug_element *elem =
>> +         (const struct gl_debug_element *) node;
>> +      struct gl_debug_element *copy;
>>
>> -      make_empty_list(&dst->Severity[sev]);
>> -      if (err)
>> -         continue;
>> -
>> -      /* copy known id severity settings */
>> -      foreach(node, &src->Severity[sev]) {
>> -         const struct gl_debug_severity *entry =
>> -            (const struct gl_debug_severity *) node;
>> -         struct gl_debug_severity *copy;
>> -
>> -         copy = malloc(sizeof(*copy));
>> -         if (!copy) {
>> -            err = true;
>> -            break;
>> -         }
>> -
>> -         copy->ID = entry->ID;
>> -         insert_at_tail(&dst->Severity[sev], &copy->link);
>> +      copy = malloc(sizeof(*copy));
>> +      if (!copy) {
>> +         debug_namespace_clear(dst);
>> +         return false;
>>         }
>> -   }
>>
>> -   if (err) {
>> -      debug_namespace_clear(dst);
>> -      return false;
>> +      copy->ID = elem->ID;
>> +      copy->State = elem->State;
>> +      insert_at_tail(&dst->Elements, &copy->link);
>>      }
>>
>>      return true;
>> @@ -367,29 +286,39 @@ static bool
>>   debug_namespace_set(struct gl_debug_namespace *ns,
>>                       GLuint id, bool enabled)
>>   {
>> -   uintptr_t state;
>> +   const uint32_t state = (enabled) ?
>> +      ((1 << MESA_DEBUG_SEVERITY_COUNT) - 1) : 0;
>> +   struct gl_debug_element *elem = NULL;
>> +   struct simple_node *node;
>> +
>> +   /* find the element */
>> +   foreach(node, &ns->Elements) {
>> +      struct gl_debug_element *tmp = (struct gl_debug_element *) node;
>> +      if (tmp->ID == id) {
>> +         elem = tmp;
>> +         break;
>> +      }
>> +   }
>>
>> -   /* In addition to not being able to store zero as a value, HashTable
>> also
>> -    * can't use zero as a key.
>> -    */
>> -   if (id)
>> -      state = (uintptr_t) _mesa_HashLookup(ns->IDs, id);
>> -   else
>> -      state = ns->ZeroID;
>> +   /* we do not need the element if it has the default state */
>> +   if (ns->DefaultState == state) {
>> +      if (elem) {
>> +         remove_from_list(&elem->link);
>> +         free(elem);
>> +      }
>> +      return true;
>> +   }
>>
>> -   if (state == NOT_FOUND)
>> -      state = enabled ? ENABLED : DISABLED;
>> -   else {
>> -      if (enabled)
>> -         state |= ENABLED_BIT;
>> -      else
>> -         state &= ~ENABLED_BIT;
>> +   if (!elem) {
>> +      elem = malloc(sizeof(*elem));
>> +      if (!elem)
>> +         return false;
>> +
>> +      elem->ID = id;
>> +      insert_at_tail(&ns->Elements, &elem->link);
>>      }
>>
>> -   if (id)
>> -      _mesa_HashInsert(ns->IDs, id, (void *) state);
>> -   else
>> -      ns->ZeroID = state;
>> +   elem->State = state;
>>
>>      return true;
>>   }
>> @@ -404,26 +333,29 @@ debug_namespace_set_all(struct gl_debug_namespace
>> *ns,
>>                           enum mesa_debug_severity severity,
>>                           bool enabled)
>>   {
>> -   int sev, end;
>> -
>> -   if (severity >= Elements(ns->Severity)) {
>> -      end = severity;
>> -      severity = 0;
>> -   } else {
>> -      end = severity + 1;
>> +   struct simple_node *node, *tmp;
>> +   uint32_t mask, val;
>> +
>> +   /* set all elements to the same state */
>> +   if (severity == MESA_DEBUG_SEVERITY_COUNT) {
>> +      ns->DefaultState = (enabled) ? ((1 << severity) - 1) : 0;
>> +      debug_namespace_clear(ns);
>> +      make_empty_list(&ns->Elements);
>> +      return;
>>      }
>>
>> -   for (sev = severity; sev < end; sev++) {
>> -      struct simple_node *node;
>> -      struct gl_debug_severity *entry;
>> +   mask = 1 << severity;
>> +   val = (enabled) ? mask : 0;
>> +
>> +   ns->DefaultState = (ns->DefaultState & ~mask) | val;
>>
>> -      /* change the default for IDs we've never seen before. */
>> -      ns->Defaults[sev] = enabled;
>> +   foreach_s(node, tmp, &ns->Elements) {
>> +      struct gl_debug_element *elem = (struct gl_debug_element *) node;
>>
>> -      /* Now change the state of IDs we *have* seen... */
>> -      foreach(node, &ns->Severity[sev]) {
>> -         entry = (struct gl_debug_severity *) node;
>> -         debug_namespace_set(ns, entry->ID, enabled);
>> +      elem->State = (elem->State & ~mask) | val;
>> +      if (elem->State == ns->DefaultState) {
>> +         remove_from_list(node);
>> +         free(node);
>>         }
>>      }
>>   }
>> @@ -432,47 +364,23 @@ debug_namespace_set_all(struct gl_debug_namespace
>> *ns,
>>    * Get the state of \p id in the namespace.
>>    */
>>   static bool
>> -debug_namespace_get(struct gl_debug_namespace *ns, GLuint id,
>> +debug_namespace_get(const struct gl_debug_namespace *ns, GLuint id,
>>                       enum mesa_debug_severity severity)
>>   {
>> -   uintptr_t state = 0;
>> +   struct simple_node *node;
>> +   uint32_t state;
>>
>> -   /* In addition to not being able to store zero as a value, HashTable
>> also
>> -    * can't use zero as a key.
>> -    */
>> -   if (id)
>> -      state = (uintptr_t) _mesa_HashLookup(ns->IDs, id);
>> -   else
>> -      state = ns->ZeroID;
>> -
>> -   /* Only do this once for each ID. This makes sure the ID exists in,
>> -    * at most, one list, and does not pointlessly appear multiple times.
>> -    */
>> -   if (!(state & KNOWN_SEVERITY)) {
>> -      struct gl_debug_severity *entry;
>> -
>> -      if (state == NOT_FOUND) {
>> -         if (ns->Defaults[severity])
>> -            state = ENABLED;
>> -         else
>> -            state = DISABLED;
>> -      }
>> +   state = ns->DefaultState;
>> +   foreach(node, &ns->Elements) {
>> +      struct gl_debug_element *elem = (struct gl_debug_element *) node;
>>
>> -      entry = malloc(sizeof *entry);
>> -      if (entry) {
>> -         state |= KNOWN_SEVERITY;
>> -
>> -         if (id)
>> -            _mesa_HashInsert(ns->IDs, id, (void *) state);
>> -         else
>> -            ns->ZeroID = state;
>> -
>> -         entry->ID = id;
>> -         insert_at_tail(&ns->Severity[severity], &entry->link);
>> +      if (elem->ID == id) {
>> +         state = elem->State;
>> +         break;
>>         }
>>      }
>>
>> -   return (state & ENABLED_BIT);
>> +   return (state & (1 << severity));
>>   }
>>
>>   /**
>> @@ -660,7 +568,7 @@ debug_set_message_enable_all(struct gl_debug_state
>> *debug,
>>    * Returns if the given message source/type/ID tuple is enabled.
>>    */
>>   static bool
>> -debug_is_message_enabled(struct gl_debug_state *debug,
>> +debug_is_message_enabled(const struct gl_debug_state *debug,
>>                            enum mesa_debug_source source,
>>                            enum mesa_debug_type type,
>>                            GLuint id,
>>
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev



-- 
olv at LunarG.com


More information about the mesa-dev mailing list