~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/util/u_debug_refcnt.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**************************************************************************
2
 
 *
3
 
 * Copyright 2010 Luca Barbieri
4
 
 *
5
 
 * Permission is hereby granted, free of charge, to any person obtaining
6
 
 * a copy of this software and associated documentation files (the
7
 
 * "Software"), to deal in the Software without restriction, including
8
 
 * without limitation the rights to use, copy, modify, merge, publish,
9
 
 * distribute, sublicense, and/or sell copies of the Software, and to
10
 
 * permit persons to whom the Software is furnished to do so, subject to
11
 
 * the following conditions:
12
 
 *
13
 
 * The above copyright notice and this permission notice (including the
14
 
 * next paragraph) shall be included in all copies or substantial
15
 
 * portions of the Software.
16
 
 *
17
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
 
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21
 
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 
 *
25
 
 **************************************************************************/
26
 
 
27
 
#if defined(DEBUG)
28
 
 
29
 
/**
30
 
 * If the GALLIUM_REFCNT_LOG env var is defined as a filename, gallium
31
 
 * reference counting will be logged to the file.
32
 
 *
33
 
 * See http://www-archive.mozilla.org/performance/refcnt-balancer.html
34
 
 * for what to do with the output on Linux, use tools/addr2line.sh to
35
 
 * postprocess it before anything else.
36
 
 */
37
 
 
38
 
#include <stdio.h>
39
 
 
40
 
#include "util/u_debug.h"
41
 
#include "util/u_debug_refcnt.h"
42
 
#include "util/u_debug_stack.h"
43
 
#include "util/u_debug_symbol.h"
44
 
#include "util/u_string.h"
45
 
#include "util/u_hash_table.h"
46
 
#include "util/u_thread.h"
47
 
 
48
 
int debug_refcnt_state;
49
 
 
50
 
static FILE *stream;
51
 
 
52
 
/* TODO: maybe move this serial machinery to a stand-alone module and
53
 
 * expose it?
54
 
 */
55
 
#ifdef PIPE_OS_WINDOWS
56
 
static mtx_t serials_mutex;
57
 
#else
58
 
static mtx_t serials_mutex = _MTX_INITIALIZER_NP;
59
 
#endif
60
 
 
61
 
static struct hash_table *serials_hash;
62
 
static unsigned serials_last;
63
 
 
64
 
 
65
 
/**
66
 
 * Return a small integer serial number for the given pointer.
67
 
 */
68
 
static boolean
69
 
debug_serial(void *p, unsigned *pserial)
70
 
{
71
 
   unsigned serial;
72
 
   boolean found = TRUE;
73
 
#ifdef PIPE_OS_WINDOWS
74
 
   static boolean first = TRUE;
75
 
 
76
 
   if (first) {
77
 
      (void) mtx_init(&serials_mutex, mtx_plain);
78
 
      first = FALSE;
79
 
   }
80
 
#endif
81
 
 
82
 
   mtx_lock(&serials_mutex);
83
 
   if (!serials_hash)
84
 
      serials_hash = util_hash_table_create_ptr_keys();
85
 
 
86
 
   serial = (unsigned) (uintptr_t) util_hash_table_get(serials_hash, p);
87
 
   if (!serial) {
88
 
      /* time to stop logging... (you'll have a 100 GB logfile at least at
89
 
       * this point)  TODO: avoid this
90
 
       */
91
 
      serial = ++serials_last;
92
 
      if (!serial) {
93
 
         debug_error("More than 2^32 objects detected, aborting.\n");
94
 
         os_abort();
95
 
      }
96
 
 
97
 
      _mesa_hash_table_insert(serials_hash, p, (void *) (uintptr_t) serial);
98
 
      found = FALSE;
99
 
   }
100
 
   mtx_unlock(&serials_mutex);
101
 
 
102
 
   *pserial = serial;
103
 
 
104
 
   return found;
105
 
}
106
 
 
107
 
 
108
 
/**
109
 
 * Free the serial number for the given pointer.
110
 
 */
111
 
static void
112
 
debug_serial_delete(void *p)
113
 
{
114
 
   mtx_lock(&serials_mutex);
115
 
   _mesa_hash_table_remove_key(serials_hash, p);
116
 
   mtx_unlock(&serials_mutex);
117
 
}
118
 
 
119
 
 
120
 
#if defined(PIPE_OS_WINDOWS)
121
 
#define STACK_LEN 60
122
 
#else
123
 
#define STACK_LEN 64
124
 
#endif
125
 
 
126
 
/**
127
 
 * Log a reference count change to the log file (if enabled).
128
 
 * This is called via the pipe_reference() and debug_reference() functions,
129
 
 * basically whenever a reference count is initialized or changed.
130
 
 *
131
 
 * \param p  the refcount being changed (the value is not changed here)
132
 
 * \param get_desc  a function which will be called to print an object's
133
 
 *                  name/pointer into a string buffer during logging
134
 
 * \param change  the reference count change which must be +/-1 or 0 when
135
 
 *                creating the object and initializing the refcount.
136
 
 */
137
 
void
138
 
debug_reference_slowpath(const struct pipe_reference *p,
139
 
                         debug_reference_descriptor get_desc, int change)
140
 
{
141
 
   assert(change >= -1);
142
 
   assert(change <= 1);
143
 
 
144
 
   if (debug_refcnt_state < 0)
145
 
      return;
146
 
 
147
 
   if (!debug_refcnt_state) {
148
 
      const char *filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL);
149
 
      if (filename && filename[0])
150
 
         stream = fopen(filename, "wt");
151
 
 
152
 
      if (stream)
153
 
         debug_refcnt_state = 1;
154
 
      else
155
 
         debug_refcnt_state = -1;
156
 
   }
157
 
 
158
 
   if (debug_refcnt_state > 0) {
159
 
      struct debug_stack_frame frames[STACK_LEN];
160
 
      char buf[1024];
161
 
      unsigned i;
162
 
      unsigned refcnt = p->count;
163
 
      unsigned serial;
164
 
      boolean existing = debug_serial((void *) p, &serial);
165
 
 
166
 
      debug_backtrace_capture(frames, 1, STACK_LEN);
167
 
 
168
 
      get_desc(buf, p);
169
 
 
170
 
      if (!existing) {
171
 
         fprintf(stream, "<%s> %p %u Create\n", buf, (void *) p, serial);
172
 
         debug_backtrace_print(stream, frames, STACK_LEN);
173
 
 
174
 
         /* this is here to provide a gradual change even if we don't see
175
 
          * the initialization
176
 
          */
177
 
         for (i = 1; i <= refcnt - change; ++i) {
178
 
            fprintf(stream, "<%s> %p %u AddRef %u\n", buf, (void *) p,
179
 
                    serial, i);
180
 
            debug_backtrace_print(stream, frames, STACK_LEN);
181
 
         }
182
 
      }
183
 
 
184
 
      if (change) {
185
 
         fprintf(stream, "<%s> %p %u %s %u\n", buf, (void *) p, serial,
186
 
                 change > 0 ? "AddRef" : "Release", refcnt);
187
 
         debug_backtrace_print(stream, frames, STACK_LEN);
188
 
      }
189
 
 
190
 
      if (!refcnt) {
191
 
         debug_serial_delete((void *) p);
192
 
         fprintf(stream, "<%s> %p %u Destroy\n", buf, (void *) p, serial);
193
 
         debug_backtrace_print(stream, frames, STACK_LEN);
194
 
      }
195
 
 
196
 
      fflush(stream);
197
 
   }
198
 
}
199
 
 
200
 
#endif /* DEBUG */