pb_bufmgr_debug.c revision e06474dbae6979177629fb6187331291ff230c65
1cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com/************************************************************************** 2cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * 3cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * All Rights Reserved. 5cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * 6cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * Permission is hereby granted, free of charge, to any person obtaining a 7cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * copy of this software and associated documentation files (the 8cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * "Software"), to deal in the Software without restriction, including 9cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * without limitation the rights to use, copy, modify, merge, publish, 10cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * distribute, sub license, and/or sell copies of the Software, and to 11cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * permit persons to whom the Software is furnished to do so, subject to 12cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * the following conditions: 13cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * 14cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * The above copyright notice and this permission notice (including the 15cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * next paragraph) shall be included in all copies or substantial portions 16a61ba109bf1a60c6de8f9ebea043e782497b88ccdjsollen@google.com * of the Software. 17cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * 18cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 237507276d8626a6d4a4073b3f93bd2eaa9f21f111commit-bot@chromium.org * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 247507276d8626a6d4a4073b3f93bd2eaa9f21f111commit-bot@chromium.org * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257507276d8626a6d4a4073b3f93bd2eaa9f21f111commit-bot@chromium.org * 26cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com **************************************************************************/ 27cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com 287507276d8626a6d4a4073b3f93bd2eaa9f21f111commit-bot@chromium.org/** 29cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * \file 30cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * Debug buffer manager to detect buffer under- and overflows. 31cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com * 327507276d8626a6d4a4073b3f93bd2eaa9f21f111commit-bot@chromium.org * \author Jose Fonseca <jrfonseca@tungstengraphics.com> 33cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com */ 34cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com 35cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com 367507276d8626a6d4a4073b3f93bd2eaa9f21f111commit-bot@chromium.org#include "pipe/p_compiler.h" 37cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "pipe/p_debug.h" 38cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "pipe/p_winsys.h" 39cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "pipe/p_thread.h" 40cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "util/u_math.h" 41cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "util/u_memory.h" 42cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "util/u_double_list.h" 43cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "util/u_time.h" 44cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com 45cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "pb_buffer.h" 46cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com#include "pb_bufmgr.h" 47cc95b1aeb8cbb9201712c9982d12149b0e0027f0djsollen@google.com 48c1dc0d486ff1f537378205a2d1698ce2044e7735commit-bot@chromium.org 49c1dc0d486ff1f537378205a2d1698ce2044e7735commit-bot@chromium.org#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 = 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(!buf->base.base.refcount); 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 = size + 2*mgr->band_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(buf->buffer->base.refcount >= 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 buf->base.base.refcount = 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->band_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, size_t band_size) 361{ 362 struct pb_debug_manager *mgr; 363 364 if(!provider) 365 return NULL; 366 367 mgr = CALLOC_STRUCT(pb_debug_manager); 368 if (!mgr) 369 return NULL; 370 371 mgr->base.destroy = pb_debug_manager_destroy; 372 mgr->base.create_buffer = pb_debug_manager_create_buffer; 373 mgr->base.flush = pb_debug_manager_flush; 374 mgr->provider = provider; 375 mgr->band_size = band_size; 376 377 return &mgr->base; 378} 379 380 381#else /* !DEBUG */ 382 383 384struct pb_manager * 385pb_debug_manager_create(struct pb_manager *provider, size_t band_size) 386{ 387 return provider; 388} 389 390 391#endif /* !DEBUG */ 392