1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/************************************************************************** 2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright 2010 Luca Barbieri 4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Permission is hereby granted, free of charge, to any person obtaining 6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * a copy of this software and associated documentation files (the 7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * "Software"), to deal in the Software without restriction, including 8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * without limitation the rights to use, copy, modify, merge, publish, 9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * distribute, sublicense, and/or sell copies of the Software, and to 10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * permit persons to whom the Software is furnished to do so, subject to 11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * the following conditions: 12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The above copyright notice and this permission notice (including the 14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * next paragraph) shall be included in all copies or substantial 15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * portions of the Software. 16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org **************************************************************************/ 26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if defined(DEBUG) 28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* see http://www.mozilla.org/performance/refcnt-balancer.html for what do with the output 30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * on Linux, use tools/addr2line.sh to postprocess it before anything else 31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org **/ 32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <stdio.h> 34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_debug.h" 36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_debug_refcnt.h" 37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_debug_stack.h" 38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_debug_symbol.h" 39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_string.h" 40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_hash_table.h" 41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "os/os_thread.h" 42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint debug_refcnt_state; 44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgFILE* stream; 46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* TODO: maybe move this serial machinery to a stand-alone module and expose it? */ 48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgpipe_static_mutex(serials_mutex); 49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct util_hash_table* serials_hash; 51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic unsigned serials_last; 52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic unsigned hash_ptr(void* p) 54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return (unsigned)(uintptr_t)p; 56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int compare_ptr(void* a, void* b) 59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(a == b) 61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return 0; 62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else if(a < b) 63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return -1; 64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else 65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return 1; 66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic boolean debug_serial(void* p, unsigned* pserial) 69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned serial; 71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org boolean found = TRUE; 72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef PIPE_SUBSYSTEM_WINDOWS_USER 73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org static boolean first = TRUE; 74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (first) { 76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org pipe_mutex_init(serials_mutex); 77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org first = FALSE; 78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif 80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org pipe_mutex_lock(serials_mutex); 82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(!serials_hash) 83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org serials_hash = util_hash_table_create(hash_ptr, compare_ptr); 84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org serial = (unsigned)(uintptr_t)util_hash_table_get(serials_hash, p); 85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(!serial) 86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* time to stop logging... (you'll have a 100 GB logfile at least at this point) 88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * TODO: avoid this 89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org serial = ++serials_last; 91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(!serial) 92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org debug_error("More than 2^32 objects detected, aborting.\n"); 94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org os_abort(); 95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org util_hash_table_set(serials_hash, p, (void*)(uintptr_t)serial); 98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org found = FALSE; 99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org pipe_mutex_unlock(serials_mutex); 101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *pserial = serial; 102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return found; 103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void debug_serial_delete(void* p) 106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org pipe_mutex_lock(serials_mutex); 108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org util_hash_table_remove(serials_hash, p); 109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org pipe_mutex_unlock(serials_mutex); 110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define STACK_LEN 64 113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void dump_stack(const char* symbols[STACK_LEN]) 115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned i; 117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for(i = 0; i < STACK_LEN; ++i) 118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(symbols[i]) 120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stream, "%s\n", symbols[i]); 121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stream, "\n"); 123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid debug_reference_slowpath(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change) 126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(debug_refcnt_state < 0) 128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return; 129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(!debug_refcnt_state) 131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char* filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL); 133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(filename && filename[0]) 134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org stream = fopen(filename, "wt"); 135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(stream) 137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org debug_refcnt_state = 1; 138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else 139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org debug_refcnt_state = -1; 140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(debug_refcnt_state > 0) 143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct debug_stack_frame frames[STACK_LEN]; 145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char* symbols[STACK_LEN]; 146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org char buf[1024]; 147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned i; 149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned refcnt = p->count; 150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned serial; 151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org boolean existing = debug_serial((void*)p, &serial); 152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org debug_backtrace_capture(frames, 1, STACK_LEN); 154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for(i = 0; i < STACK_LEN; ++i) 155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(frames[i].function) 157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org symbols[i] = debug_symbol_name_cached(frames[i].function); 158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else 159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org symbols[i] = 0; 160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org get_desc(buf, p); 163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(!existing) 165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stream, "<%s> %p %u Create\n", buf, (void *) p, serial); 167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dump_stack(symbols); 168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* this is there to provide a gradual change even if we don't see the initialization */ 170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for(i = 1; i <= refcnt - change; ++i) 171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stream, "<%s> %p %u AddRef %u\n", buf, (void *) p, 173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org serial, i); 174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dump_stack(symbols); 175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(change) 179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stream, "<%s> %p %u %s %u\n", buf, (void *) p, serial, 181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org change > 0 ? "AddRef" : "Release", refcnt); 182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dump_stack(symbols); 183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if(!refcnt) 186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org { 187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org debug_serial_delete((void*)p); 188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stream, "<%s> %p %u Destroy\n", buf, (void *) p, serial); 189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dump_stack(symbols); 190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fflush(stream); 193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif 196