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