u_debug_refcnt.c revision 52ad45677dd3d8a50836edea9f5841aa12d70419
169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com/**************************************************************************
2b0c97975894a5eebebf9d93147cdd941a3accb63fbarchard@google.com *
369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * Copyright 2010 Luca Barbieri
469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *
569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * Permission is hereby granted, free of charge, to any person obtaining
669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * a copy of this software and associated documentation files (the
7cde587092fef0dbed2c35602f30b79e7b892e766fbarchard@google.com * "Software"), to deal in the Software without restriction, including
869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * without limitation the rights to use, copy, modify, merge, publish,
969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * distribute, sublicense, and/or sell copies of the Software, and to
1069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * permit persons to whom the Software is furnished to do so, subject to
1169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * the following conditions:
1269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *
1364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com * The above copyright notice and this permission notice (including the
1469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * next paragraph) shall be included in all copies or substantial
152c8108e6c2c6fa0c62670a70be7ef6f59cf03848fbarchard@google.com * portions of the Software.
162c8108e6c2c6fa0c62670a70be7ef6f59cf03848fbarchard@google.com *
172c8108e6c2c6fa0c62670a70be7ef6f59cf03848fbarchard@google.com * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18d7c7bfac57ce1775d6424865d8d4ec8b278070bafbarchard@google.com * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22d7c7bfac57ce1775d6424865d8d4ec8b278070bafbarchard@google.com * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com *
25ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com **************************************************************************/
26ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com
27ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#if defined(DEBUG) && (!defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_WINDOWS_USER))
28ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com
2969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com/* see http://www.mozilla.org/performance/refcnt-balancer.html for what do with the output
3069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com * on Linux, use tools/addr2line.sh to postprocess it before anything else
31ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com **/
32ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#include <util/u_debug.h>
33ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#include <util/u_debug_refcnt.h>
34ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#include <util/u_debug_stack.h>
35d7c7bfac57ce1775d6424865d8d4ec8b278070bafbarchard@google.com#include <util/u_debug_symbol.h>
36e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com#include <util/u_string.h>
3769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#include <util/u_hash_table.h>
3869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#include <os/os_thread.h>
39133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#include <os/os_stream.h>
4069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint debug_refcnt_state;
4269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstruct os_stream* stream;
44133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com
4569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com/* TODO: maybe move this serial machinery to a stand-alone module and expose it? */
4669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.compipe_static_mutex(serials_mutex);
4769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic struct util_hash_table* serials_hash;
4969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic unsigned serials_last;
5069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
5169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic unsigned hash_ptr(void* p)
5269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com{
538b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com   return (unsigned)(uintptr_t)p;
548b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com}
558b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com
568b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comstatic int compare_ptr(void* a, void* b)
578b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com{
588b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com   if(a == b)
598b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com      return 0;
608b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com   else if(a < b)
6169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return -1;
62db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com   else
6369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return 1;
6469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
6569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
6669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic boolean debug_serial(void* p, unsigned* pserial)
6769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com{
68e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com   unsigned serial;
69e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com   boolean found = TRUE;
70133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef PIPE_SUBSYSTEM_WINDOWS_USER
71e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com   static boolean first = TRUE;
7269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
7369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   if (first) {
7469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      pipe_mutex_init(serials_mutex);
75133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com      first = FALSE;
7669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   }
7769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#endif
7869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
7969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   pipe_mutex_lock(serials_mutex);
8069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   if(!serials_hash)
8169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      serials_hash = util_hash_table_create(hash_ptr, compare_ptr);
82e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com   serial = (unsigned)(uintptr_t)util_hash_table_get(serials_hash, p);
83e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com   if(!serial)
8469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   {
8569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      /* time to stop logging... (you'll have a 100 GB logfile at least at this point)
8669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com       * TODO: avoid this
8769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com       */
8869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      serial = ++serials_last;
89e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com      if(!serial)
90e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com      {
91e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com         debug_error("More than 2^32 objects detected, aborting.\n");
92133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com         os_abort();
93e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com      }
94133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com
9569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      util_hash_table_set(serials_hash, p, (void*)(uintptr_t)serial);
9669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      found = FALSE;
9769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   }
98db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com   pipe_mutex_unlock(serials_mutex);
9969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   *pserial = serial;
100db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com   return found;
10169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
10269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
10369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic void debug_serial_delete(void* p)
104a1f5254a955c5c32484b56822596a4e3368e8eb7fbarchard@google.com{
10569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   pipe_mutex_lock(serials_mutex);
10669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   util_hash_table_remove(serials_hash, p);
107133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com   pipe_mutex_unlock(serials_mutex);
10869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
10969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
11069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#define STACK_LEN 64
111db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com
11269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic void dump_stack(const char* symbols[STACK_LEN])
113133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com{
114e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com   unsigned i;
11569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   for(i = 0; i < STACK_LEN; ++i)
116db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com   {
11769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if(symbols[i])
11869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         os_stream_printf(stream, "%s\n", symbols[i]);
11969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   }
12069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   os_stream_write(stream, "\n", 1);
12169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
12269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
12369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comvoid debug_reference_slowpath(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change)
12469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com{
12569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   if(debug_refcnt_state < 0)
12669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return;
12769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
12869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   if(!debug_refcnt_state)
12969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   {
13069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      const char* filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL);
13169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if(filename && filename[0])
13269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         stream = os_file_stream_create(filename);
13369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
13469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if(stream)
13569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         debug_refcnt_state = 1;
13669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      else
13769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         debug_refcnt_state = -1;
13869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   }
13969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
14069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   if(debug_refcnt_state > 0)
14169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   {
14269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      struct debug_stack_frame frames[STACK_LEN];
14369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      const char* symbols[STACK_LEN];
14469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      char buf[1024];
14569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
146db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      unsigned i;
14769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      unsigned refcnt = p->count;
14869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      unsigned serial;
149db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      boolean existing = debug_serial((void*)p, &serial);
15069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
15169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      debug_backtrace_capture(frames, 1, STACK_LEN);
15269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      for(i = 0; i < STACK_LEN; ++i)
15369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      {
15469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         if(frames[i].function)
15569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com            symbols[i] = debug_symbol_name_cached(frames[i].function);
15669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         else
15769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com            symbols[i] = 0;
15869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
15969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
16069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      get_desc(buf, p);
16169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
16269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if(!existing)
16369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      {
16469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         os_stream_printf(stream, "<%s> %p %u Create\n", buf, p, serial);
16569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         dump_stack(symbols);
16669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
16769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         /* this is there to provide a gradual change even if we don't see the initialization */
16869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         for(i = 1; i <= refcnt - change; ++i)
16969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         {
17069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com            os_stream_printf(stream, "<%s> %p %u AddRef %u\n", buf, p, serial, i);
17169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com            dump_stack(symbols);
17269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         }
17369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
17469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
17569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if(change)
17669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      {
17769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         os_stream_printf(stream, "<%s> %p %u %s %u\n", buf, p, serial, change > 0 ? "AddRef" : "Release", refcnt);
17869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         dump_stack(symbols);
17969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
18069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
18169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if(!refcnt)
18269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      {
18369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         debug_serial_delete((void*)p);
18469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         os_stream_printf(stream, "<%s> %p %u Destroy\n", buf, p, serial);
18569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         dump_stack(symbols);
18669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
18769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
18869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      os_stream_flush(stream);
18969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com   }
19069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
19169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#endif
19269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com