pb_bufmgr_debug.c revision ea4bf267e4b023b08043f91ac44592fed1736e7f
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 Jose Fonseca <jrfonseca@tungstengraphics.com>
33 */
34
35
36#include "pipe/p_compiler.h"
37#include "util/u_debug.h"
38#include "pipe/p_thread.h"
39#include "util/u_math.h"
40#include "util/u_memory.h"
41#include "util/u_double_list.h"
42#include "util/u_time.h"
43
44#include "pb_buffer.h"
45#include "pb_bufmgr.h"
46
47
48#ifdef DEBUG
49
50
51/**
52 * Convenience macro (type safe).
53 */
54#define SUPER(__derived) (&(__derived)->base)
55
56
57struct pb_debug_manager;
58
59
60/**
61 * Wrapper around a pipe buffer which adds delayed destruction.
62 */
63struct pb_debug_buffer
64{
65   struct pb_buffer base;
66
67   struct pb_buffer *buffer;
68   struct pb_debug_manager *mgr;
69
70   size_t underflow_size;
71   size_t overflow_size;
72};
73
74
75struct pb_debug_manager
76{
77   struct pb_manager base;
78
79   struct pb_manager *provider;
80
81   size_t band_size;
82};
83
84
85static INLINE struct pb_debug_buffer *
86pb_debug_buffer(struct pb_buffer *buf)
87{
88   assert(buf);
89   return (struct pb_debug_buffer *)buf;
90}
91
92
93static INLINE struct pb_debug_manager *
94pb_debug_manager(struct pb_manager *mgr)
95{
96   assert(mgr);
97   return (struct pb_debug_manager *)mgr;
98}
99
100
101static const uint8_t random_pattern[32] = {
102   0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
103   0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
104   0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
105   0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
106};
107
108
109static INLINE void
110fill_random_pattern(uint8_t *dst, size_t size)
111{
112   size_t i = 0;
113   while(size--) {
114      *dst++ = random_pattern[i++];
115      i &= sizeof(random_pattern) - 1;
116   }
117}
118
119
120static INLINE boolean
121check_random_pattern(const uint8_t *dst, size_t size,
122                     size_t *min_ofs, size_t *max_ofs)
123{
124   boolean result = TRUE;
125   size_t i;
126   *min_ofs = size;
127   *max_ofs = 0;
128   for(i = 0; i < size; ++i) {
129      if(*dst++ != random_pattern[i % sizeof(random_pattern)]) {
130         *min_ofs = MIN2(*min_ofs, i);
131         *max_ofs = MAX2(*max_ofs, i);
132	 result = FALSE;
133      }
134   }
135   return result;
136}
137
138
139static void
140pb_debug_buffer_fill(struct pb_debug_buffer *buf)
141{
142   uint8_t *map;
143
144   map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
145   assert(map);
146   if(map) {
147      fill_random_pattern(map, buf->underflow_size);
148      fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
149                          buf->overflow_size);
150      pb_unmap(buf->buffer);
151   }
152}
153
154
155/**
156 * Check for under/over flows.
157 *
158 * Should be called with the buffer unmaped.
159 */
160static void
161pb_debug_buffer_check(struct pb_debug_buffer *buf)
162{
163   uint8_t *map;
164
165   map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_READ);
166   assert(map);
167   if(map) {
168      boolean underflow, overflow;
169      size_t min_ofs, max_ofs;
170
171      underflow = !check_random_pattern(map, buf->underflow_size,
172                                        &min_ofs, &max_ofs);
173      if(underflow) {
174         debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
175                      buf->underflow_size - min_ofs,
176                      min_ofs == 0 ? "+" : "",
177                      buf->underflow_size - max_ofs);
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 (size %u plus offset %u to %u%s bytes) detected\n",
185                      buf->base.base.size,
186                      min_ofs,
187                      max_ofs,
188                      max_ofs == buf->overflow_size - 1 ? "+" : "");
189      }
190
191      debug_assert(!underflow && !overflow);
192
193      /* re-fill if not aborted */
194      if(underflow)
195         fill_random_pattern(map, buf->underflow_size);
196      if(overflow)
197         fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
198                             buf->overflow_size);
199
200      pb_unmap(buf->buffer);
201   }
202}
203
204
205static void
206pb_debug_buffer_destroy(struct pb_buffer *_buf)
207{
208   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
209
210   assert(!buf->base.base.refcount);
211
212   pb_debug_buffer_check(buf);
213
214   pb_reference(&buf->buffer, NULL);
215   FREE(buf);
216}
217
218
219static void *
220pb_debug_buffer_map(struct pb_buffer *_buf,
221                    unsigned flags)
222{
223   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
224   void *map;
225
226   pb_debug_buffer_check(buf);
227
228   map = pb_map(buf->buffer, flags);
229   if(!map)
230      return NULL;
231
232   return (uint8_t *)map + buf->underflow_size;
233}
234
235
236static void
237pb_debug_buffer_unmap(struct pb_buffer *_buf)
238{
239   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
240   pb_unmap(buf->buffer);
241
242   pb_debug_buffer_check(buf);
243}
244
245
246static void
247pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
248                                struct pb_buffer **base_buf,
249                                unsigned *offset)
250{
251   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
252   pb_get_base_buffer(buf->buffer, base_buf, offset);
253   *offset += buf->underflow_size;
254}
255
256
257static enum pipe_error
258pb_debug_buffer_validate(struct pb_buffer *_buf,
259                         struct pb_validate *vl,
260                         unsigned flags)
261{
262   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
263
264   pb_debug_buffer_check(buf);
265
266   return pb_validate(buf->buffer, vl, flags);
267}
268
269
270static void
271pb_debug_buffer_fence(struct pb_buffer *_buf,
272                      struct pipe_fence_handle *fence)
273{
274   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
275   pb_fence(buf->buffer, fence);
276}
277
278
279const struct pb_vtbl
280pb_debug_buffer_vtbl = {
281      pb_debug_buffer_destroy,
282      pb_debug_buffer_map,
283      pb_debug_buffer_unmap,
284      pb_debug_buffer_validate,
285      pb_debug_buffer_fence,
286      pb_debug_buffer_get_base_buffer
287};
288
289
290static struct pb_buffer *
291pb_debug_manager_create_buffer(struct pb_manager *_mgr,
292                               size_t size,
293                               const struct pb_desc *desc)
294{
295   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
296   struct pb_debug_buffer *buf;
297   struct pb_desc real_desc;
298   size_t real_size;
299
300   buf = CALLOC_STRUCT(pb_debug_buffer);
301   if(!buf)
302      return NULL;
303
304   real_size = size + 2*mgr->band_size;
305   real_desc = *desc;
306   real_desc.usage |= PIPE_BUFFER_USAGE_CPU_WRITE;
307   real_desc.usage |= PIPE_BUFFER_USAGE_CPU_READ;
308
309   buf->buffer = mgr->provider->create_buffer(mgr->provider,
310                                              real_size,
311                                              &real_desc);
312   if(!buf->buffer) {
313      FREE(buf);
314      return NULL;
315   }
316
317   assert(buf->buffer->base.refcount >= 1);
318   assert(pb_check_alignment(real_desc.alignment, buf->buffer->base.alignment));
319   assert(pb_check_usage(real_desc.usage, buf->buffer->base.usage));
320   assert(buf->buffer->base.size >= real_size);
321
322   buf->base.base.refcount = 1;
323   buf->base.base.alignment = desc->alignment;
324   buf->base.base.usage = desc->usage;
325   buf->base.base.size = size;
326
327   buf->base.vtbl = &pb_debug_buffer_vtbl;
328   buf->mgr = mgr;
329
330   buf->underflow_size = mgr->band_size;
331   buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size;
332
333   pb_debug_buffer_fill(buf);
334
335   return &buf->base;
336}
337
338
339static void
340pb_debug_manager_flush(struct pb_manager *_mgr)
341{
342   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
343   assert(mgr->provider->flush);
344   if(mgr->provider->flush)
345      mgr->provider->flush(mgr->provider);
346}
347
348
349static void
350pb_debug_manager_destroy(struct pb_manager *_mgr)
351{
352   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
353   mgr->provider->destroy(mgr->provider);
354   FREE(mgr);
355}
356
357
358struct pb_manager *
359pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
360{
361   struct pb_debug_manager *mgr;
362
363   if(!provider)
364      return NULL;
365
366   mgr = CALLOC_STRUCT(pb_debug_manager);
367   if (!mgr)
368      return NULL;
369
370   mgr->base.destroy = pb_debug_manager_destroy;
371   mgr->base.create_buffer = pb_debug_manager_create_buffer;
372   mgr->base.flush = pb_debug_manager_flush;
373   mgr->provider = provider;
374   mgr->band_size = band_size;
375
376   return &mgr->base;
377}
378
379
380#else /* !DEBUG */
381
382
383struct pb_manager *
384pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
385{
386   return provider;
387}
388
389
390#endif /* !DEBUG */
391