pb_bufmgr_debug.c revision cf25ef9072f5290d228a381727c4ff921b0c60d6
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 underflow_size;
82   size_t overflow_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 = MAX2(*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 (offset -%u%s to -%u bytes) detected\n",
176                      buf->underflow_size - min_ofs,
177                      min_ofs == 0 ? "+" : "",
178                      buf->underflow_size - max_ofs);
179      }
180
181      overflow = !check_random_pattern(map + buf->underflow_size + buf->base.base.size,
182                                       buf->overflow_size,
183                                       &min_ofs, &max_ofs);
184      if(overflow) {
185         debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
186                      buf->base.base.size,
187                      min_ofs,
188                      max_ofs,
189                      max_ofs == buf->overflow_size - 1 ? "+" : "");
190      }
191
192      debug_assert(!underflow && !overflow);
193
194      /* re-fill if not aborted */
195      if(underflow)
196         fill_random_pattern(map, buf->underflow_size);
197      if(overflow)
198         fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
199                             buf->overflow_size);
200
201      pb_unmap(buf->buffer);
202   }
203}
204
205
206static void
207pb_debug_buffer_destroy(struct pb_buffer *_buf)
208{
209   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
210
211   assert(p_atomic_read(&buf->base.base.reference.count) == 0);
212
213   pb_debug_buffer_check(buf);
214
215   pb_reference(&buf->buffer, NULL);
216   FREE(buf);
217}
218
219
220static void *
221pb_debug_buffer_map(struct pb_buffer *_buf,
222                    unsigned flags)
223{
224   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
225   void *map;
226
227   pb_debug_buffer_check(buf);
228
229   map = pb_map(buf->buffer, flags);
230   if(!map)
231      return NULL;
232
233   return (uint8_t *)map + buf->underflow_size;
234}
235
236
237static void
238pb_debug_buffer_unmap(struct pb_buffer *_buf)
239{
240   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
241   pb_unmap(buf->buffer);
242
243   pb_debug_buffer_check(buf);
244}
245
246
247static void
248pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
249                                struct pb_buffer **base_buf,
250                                unsigned *offset)
251{
252   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
253   pb_get_base_buffer(buf->buffer, base_buf, offset);
254   *offset += buf->underflow_size;
255}
256
257
258static enum pipe_error
259pb_debug_buffer_validate(struct pb_buffer *_buf,
260                         struct pb_validate *vl,
261                         unsigned flags)
262{
263   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
264
265   pb_debug_buffer_check(buf);
266
267   return pb_validate(buf->buffer, vl, flags);
268}
269
270
271static void
272pb_debug_buffer_fence(struct pb_buffer *_buf,
273                      struct pipe_fence_handle *fence)
274{
275   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
276   pb_fence(buf->buffer, fence);
277}
278
279
280const struct pb_vtbl
281pb_debug_buffer_vtbl = {
282      pb_debug_buffer_destroy,
283      pb_debug_buffer_map,
284      pb_debug_buffer_unmap,
285      pb_debug_buffer_validate,
286      pb_debug_buffer_fence,
287      pb_debug_buffer_get_base_buffer
288};
289
290
291static struct pb_buffer *
292pb_debug_manager_create_buffer(struct pb_manager *_mgr,
293                               size_t size,
294                               const struct pb_desc *desc)
295{
296   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
297   struct pb_debug_buffer *buf;
298   struct pb_desc real_desc;
299   size_t real_size;
300
301   buf = CALLOC_STRUCT(pb_debug_buffer);
302   if(!buf)
303      return NULL;
304
305   real_size = mgr->underflow_size + size + mgr->overflow_size;
306   real_desc = *desc;
307   real_desc.usage |= PIPE_BUFFER_USAGE_CPU_WRITE;
308   real_desc.usage |= PIPE_BUFFER_USAGE_CPU_READ;
309
310   buf->buffer = mgr->provider->create_buffer(mgr->provider,
311                                              real_size,
312                                              &real_desc);
313   if(!buf->buffer) {
314      FREE(buf);
315      return NULL;
316   }
317
318   assert(p_atomic_read(&buf->buffer->base.reference.count) >= 1);
319   assert(pb_check_alignment(real_desc.alignment, buf->buffer->base.alignment));
320   assert(pb_check_usage(real_desc.usage, buf->buffer->base.usage));
321   assert(buf->buffer->base.size >= real_size);
322
323   pipe_reference_init(&buf->base.base.reference, 1);
324   buf->base.base.alignment = desc->alignment;
325   buf->base.base.usage = desc->usage;
326   buf->base.base.size = size;
327
328   buf->base.vtbl = &pb_debug_buffer_vtbl;
329   buf->mgr = mgr;
330
331   buf->underflow_size = mgr->underflow_size;
332   buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size;
333
334   pb_debug_buffer_fill(buf);
335
336   return &buf->base;
337}
338
339
340static void
341pb_debug_manager_flush(struct pb_manager *_mgr)
342{
343   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
344   assert(mgr->provider->flush);
345   if(mgr->provider->flush)
346      mgr->provider->flush(mgr->provider);
347}
348
349
350static void
351pb_debug_manager_destroy(struct pb_manager *_mgr)
352{
353   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
354   mgr->provider->destroy(mgr->provider);
355   FREE(mgr);
356}
357
358
359struct pb_manager *
360pb_debug_manager_create(struct pb_manager *provider,
361                        size_t underflow_size, size_t overflow_size)
362{
363   struct pb_debug_manager *mgr;
364
365   if(!provider)
366      return NULL;
367
368   mgr = CALLOC_STRUCT(pb_debug_manager);
369   if (!mgr)
370      return NULL;
371
372   mgr->base.destroy = pb_debug_manager_destroy;
373   mgr->base.create_buffer = pb_debug_manager_create_buffer;
374   mgr->base.flush = pb_debug_manager_flush;
375   mgr->provider = provider;
376   mgr->underflow_size = underflow_size;
377   mgr->overflow_size = overflow_size;
378
379   return &mgr->base;
380}
381
382
383#else /* !DEBUG */
384
385
386struct pb_manager *
387pb_debug_manager_create(struct pb_manager *provider,
388                        size_t underflow_size, size_t overflow_size)
389{
390   return provider;
391}
392
393
394#endif /* !DEBUG */
395