pb_bufmgr_debug.c revision c6739e8cea287e17b248120e1a76480f1a25c082
1/**************************************************************************
2 *
3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/**
29 * \file
30 * Debug buffer manager to detect buffer under- and overflows.
31 *
32 * \author José Fonseca <jrfonseca@tungstengraphics.com>
33 */
34
35
36#include "pipe/p_compiler.h"
37#include "pipe/p_debug.h"
38#include "pipe/p_winsys.h"
39#include "pipe/p_thread.h"
40#include "util/u_math.h"
41#include "util/u_memory.h"
42#include "util/u_double_list.h"
43#include "util/u_time.h"
44
45#include "pb_buffer.h"
46#include "pb_bufmgr.h"
47
48
49#ifdef DEBUG
50
51
52/**
53 * Convenience macro (type safe).
54 */
55#define SUPER(__derived) (&(__derived)->base)
56
57
58struct pb_debug_manager;
59
60
61/**
62 * Wrapper around a pipe buffer which adds delayed destruction.
63 */
64struct pb_debug_buffer
65{
66   struct pb_buffer base;
67
68   struct pb_buffer *buffer;
69   struct pb_debug_manager *mgr;
70
71   size_t underflow_size;
72   size_t overflow_size;
73};
74
75
76struct pb_debug_manager
77{
78   struct pb_manager base;
79
80   struct pb_manager *provider;
81
82   size_t band_size;
83};
84
85
86static INLINE struct pb_debug_buffer *
87pb_debug_buffer(struct pb_buffer *buf)
88{
89   assert(buf);
90   return (struct pb_debug_buffer *)buf;
91}
92
93
94static INLINE struct pb_debug_manager *
95pb_debug_manager(struct pb_manager *mgr)
96{
97   assert(mgr);
98   return (struct pb_debug_manager *)mgr;
99}
100
101
102static const uint8_t random_pattern[32] = {
103   0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
104   0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
105   0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
106   0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
107};
108
109
110static INLINE void
111fill_random_pattern(uint8_t *dst, size_t size)
112{
113   size_t i = 0;
114   while(size--) {
115      *dst++ = random_pattern[i++];
116      i &= sizeof(random_pattern) - 1;
117   }
118}
119
120
121static INLINE boolean
122check_random_pattern(const uint8_t *dst, size_t size,
123                     size_t *min_ofs, size_t *max_ofs)
124{
125   boolean result = TRUE;
126   size_t i;
127   *min_ofs = size;
128   *max_ofs = 0;
129   for(i = 0; i < size; ++i) {
130      if(*dst++ != random_pattern[i % sizeof(random_pattern)]) {
131         *min_ofs = MIN2(*min_ofs, i);
132         *max_ofs = MIN2(*max_ofs, i);
133	 result = FALSE;
134      }
135   }
136   return result;
137}
138
139
140static void
141pb_debug_buffer_fill(struct pb_debug_buffer *buf)
142{
143   uint8_t *map;
144
145   map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
146   assert(map);
147   if(map) {
148      fill_random_pattern(map, buf->underflow_size);
149      fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
150                          buf->overflow_size);
151      pb_unmap(buf->buffer);
152   }
153}
154
155
156/**
157 * Check for under/over flows.
158 *
159 * Should be called with the buffer unmaped.
160 */
161static void
162pb_debug_buffer_check(struct pb_debug_buffer *buf)
163{
164   uint8_t *map;
165
166   map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_READ);
167   assert(map);
168   if(map) {
169      boolean underflow, overflow;
170      size_t min_ofs, max_ofs;
171
172      underflow = !check_random_pattern(map, buf->underflow_size,
173                                        &min_ofs, &max_ofs);
174      if(underflow) {
175         debug_printf("buffer underflow (%u of %u bytes) detected\n",
176                      buf->underflow_size - min_ofs,
177                      buf->underflow_size);
178      }
179
180      overflow = !check_random_pattern(map + buf->underflow_size + buf->base.base.size,
181                                       buf->overflow_size,
182                                       &min_ofs, &max_ofs);
183      if(overflow) {
184         debug_printf("buffer overflow (%u of %u bytes) detected\n",
185                      max_ofs,
186                      buf->overflow_size);
187      }
188
189      debug_assert(!underflow && !overflow);
190
191      /* re-fill if not aborted */
192      if(underflow)
193         fill_random_pattern(map, buf->underflow_size);
194      if(overflow)
195         fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
196                             buf->overflow_size);
197
198      pb_unmap(buf->buffer);
199   }
200}
201
202
203static void
204pb_debug_buffer_destroy(struct pb_buffer *_buf)
205{
206   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
207
208   assert(!buf->base.base.refcount);
209
210   pb_debug_buffer_check(buf);
211
212   pb_reference(&buf->buffer, NULL);
213   FREE(buf);
214}
215
216
217static void *
218pb_debug_buffer_map(struct pb_buffer *_buf,
219                    unsigned flags)
220{
221   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
222   void *map;
223
224   pb_debug_buffer_check(buf);
225
226   map = pb_map(buf->buffer, flags);
227   if(!map)
228      return NULL;
229
230   return (uint8_t *)map + buf->underflow_size;
231}
232
233
234static void
235pb_debug_buffer_unmap(struct pb_buffer *_buf)
236{
237   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
238   pb_unmap(buf->buffer);
239
240   pb_debug_buffer_check(buf);
241}
242
243
244static void
245pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
246                                struct pb_buffer **base_buf,
247                                unsigned *offset)
248{
249   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
250   pb_get_base_buffer(buf->buffer, base_buf, offset);
251   *offset += buf->underflow_size;
252}
253
254
255const struct pb_vtbl
256pb_debug_buffer_vtbl = {
257      pb_debug_buffer_destroy,
258      pb_debug_buffer_map,
259      pb_debug_buffer_unmap,
260      pb_debug_buffer_get_base_buffer
261};
262
263
264static struct pb_buffer *
265pb_debug_manager_create_buffer(struct pb_manager *_mgr,
266                               size_t size,
267                               const struct pb_desc *desc)
268{
269   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
270   struct pb_debug_buffer *buf;
271   struct pb_desc real_desc;
272   size_t real_size;
273
274   buf = CALLOC_STRUCT(pb_debug_buffer);
275   if(!buf)
276      return NULL;
277
278   real_size = size + 2*mgr->band_size;
279   real_desc = *desc;
280   real_desc.usage |= PIPE_BUFFER_USAGE_CPU_WRITE;
281   real_desc.usage |= PIPE_BUFFER_USAGE_CPU_READ;
282
283   buf->buffer = mgr->provider->create_buffer(mgr->provider,
284                                              real_size,
285                                              &real_desc);
286   if(!buf->buffer) {
287      FREE(buf);
288      return NULL;
289   }
290
291   assert(buf->buffer->base.refcount >= 1);
292   assert(pb_check_alignment(real_desc.alignment, buf->buffer->base.alignment));
293   assert(pb_check_usage(real_desc.usage, buf->buffer->base.usage));
294   assert(buf->buffer->base.size >= real_size);
295
296   buf->base.base.refcount = 1;
297   buf->base.base.alignment = desc->alignment;
298   buf->base.base.usage = desc->usage;
299   buf->base.base.size = size;
300
301   buf->base.vtbl = &pb_debug_buffer_vtbl;
302   buf->mgr = mgr;
303
304   buf->underflow_size = mgr->band_size;
305   buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size;
306
307   pb_debug_buffer_fill(buf);
308
309   return &buf->base;
310}
311
312
313static void
314pb_debug_manager_destroy(struct pb_manager *_mgr)
315{
316   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
317   mgr->provider->destroy(mgr->provider);
318   FREE(mgr);
319}
320
321
322struct pb_manager *
323pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
324{
325   struct pb_debug_manager *mgr;
326
327   if(!provider)
328      return NULL;
329
330   mgr = CALLOC_STRUCT(pb_debug_manager);
331   if (!mgr)
332      return NULL;
333
334   mgr->base.destroy = pb_debug_manager_destroy;
335   mgr->base.create_buffer = pb_debug_manager_create_buffer;
336   mgr->provider = provider;
337   mgr->band_size = band_size;
338
339   return &mgr->base;
340}
341
342
343#else /* !DEBUG */
344
345
346struct pb_manager *
347pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
348{
349   return provider;
350}
351
352
353#endif /* !DEBUG */
354