1
0
forked from 0ad/0ad

ogl, h_mgr: tag-ified debug_printf string for use with new filter

debug: filter mechanism now usable. added docs

This was SVN commit r3001.
This commit is contained in:
janwas 2005-10-24 17:38:22 +00:00
parent 7cb003f18c
commit d49dd25385
4 changed files with 61 additions and 17 deletions

View File

@ -83,13 +83,13 @@ static const int MAX_CHARS = 512;
// rationale: static data instead of std::set to allow setting at any time. // rationale: static data instead of std::set to allow setting at any time.
// note: need only set the pointer, but strcmp when reading (because // we store FNV hash of tag strings for fast comparison; collisions are
// 2 different call sites may have used equal literals at different addresses). // extremely unlikely.
static const uint MAX_TAGS = 20; static const uint MAX_TAGS = 20;
static u32 tags[MAX_TAGS]; static u32 tags[MAX_TAGS];
static uint num_tags; static uint num_tags;
static void filter_add(const char* tag) void debug_filter_add(const char* tag)
{ {
const u32 hash = fnv_hash(tag); const u32 hash = fnv_hash(tag);
@ -108,11 +108,12 @@ static void filter_add(const char* tag)
tags[num_tags++] = hash; tags[num_tags++] = hash;
} }
static void filter_remove(const char* tag) void debug_filter_remove(const char* tag)
{ {
const u32 hash = fnv_hash(tag); const u32 hash = fnv_hash(tag);
for(uint i = 0; i < MAX_TAGS; i++) for(uint i = 0; i < MAX_TAGS; i++)
// found it
if(tags[i] == hash) if(tags[i] == hash)
{ {
// replace with last element (avoid holes) // replace with last element (avoid holes)
@ -124,12 +125,18 @@ static void filter_remove(const char* tag)
} }
} }
void debug_filter_clear()
{
for(uint i = 0; i < MAX_TAGS; i++)
tags[i] = 0;
}
static bool filter_allows(const char* text) static bool filter_allows(const char* text)
{ {
uint i; uint i;
for(i = 0; ; i++) for(i = 0; ; i++)
{ {
// .. no colon - should be displayed // no colon found => no tag => should always be displayed
if(text[i] == ' ' || text[i] == '\0') if(text[i] == ' ' || text[i] == '\0')
return true; return true;
if(text[i] == ':' && i != 0) if(text[i] == ':' && i != 0)
@ -138,7 +145,7 @@ static bool filter_allows(const char* text)
const u32 hash = fnv_hash(text, i); const u32 hash = fnv_hash(text, i);
// check if allow-entry is found // check if entry allowing this tag is found
for(i = 0; i < MAX_TAGS; i++) for(i = 0; i < MAX_TAGS; i++)
if(tags[i] == hash) if(tags[i] == hash)
return true; return true;

View File

@ -153,19 +153,52 @@ extern enum ErrorReaction debug_assert_failed(const char* file, int line,
// we therefore just squelch the warning (unfortunately non-portable). // we therefore just squelch the warning (unfortunately non-portable).
#define debug_warn(str) debug_assert((str) && 0) #define debug_warn(str) debug_assert((str) && 0)
extern void debug_puts(const char* text); // write a formatted string to the debug channel, subject to filtering
extern void debug_putws(const wchar_t* text); // (see below). implemented via debug_puts - see performance note there.
// write to the debugger output window (may take ~1 ms!)
extern void debug_printf(const char* fmt, ...); extern void debug_printf(const char* fmt, ...);
// note: this merely converts to a MBS and calls debug_printf.
extern void debug_wprintf(const wchar_t* fmt, ...); extern void debug_wprintf(const wchar_t* fmt, ...);
//
// filtering
//
// debug output is very useful, but "too much of a good thing can kill you".
// we don't want to require different LOGn() macros that are enabled
// depending on "debug level", because changing that entails lengthy
// compiles and it's too coarse-grained. instead, we require all
// strings to start with "tag_string:" (exact case and no quotes;
// the alphanumeric-only <tag_string> identifies output type).
// they are then subject to filtering: only if the tag has been
// "added" via debug_filter_add is the appendant string displayed.
//
// this approach is easiest to implement and is fine because we control
// all logging code. LIMODS falls from consideration since it's not
// portable and too complex.
//
// notes:
// - filter changes only affect subsequent debug_*printf calls;
// output that didn't pass the filter is permanently discarded.
// - strings not starting with a tag are always displayed.
// - debug_filter_* can be called at any time and from the debugger.
// in future, allow output with the given tag to proceed.
// no effect if already added.
extern void debug_filter_add(const char* tag);
// in future, discard output with the given tag.
// no effect if not currently added.
extern void debug_filter_remove(const char* tag);
// clear all filter state; equivalent to debug_filter_remove for
// each tag that was debug_filter_add-ed.
extern void debug_filter_clear();
// write to memory buffer (fast) // write to memory buffer (fast)
// used for "last activity" reporting in the crashlog. // used for "last activity" reporting in the crashlog.
extern void debug_wprintf_mem(const wchar_t* fmt, ...); extern void debug_wprintf_mem(const wchar_t* fmt, ...);
// write all logs and <text> out to crashlog.txt (unicode format). // write all logs and <text> out to crashlog.txt (unicode format).
// currently all filenames are hardcoded; this may change.
extern int debug_write_crashlog(const wchar_t* text); extern int debug_write_crashlog(const wchar_t* text);
@ -244,6 +277,11 @@ extern const wchar_t* debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip
// helper functions (used by implementation) // helper functions (used by implementation)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [system-dependent] write a string to the debug channel.
// this can be quite slow (~1 ms)! On Windows, it uses OutputDebugString
// (entails context switch), otherwise stdout+fflush (waits for IO).
extern void debug_puts(const char* text);
// abstraction of all STL iterators used by debug_stl. // abstraction of all STL iterators used by debug_stl.
typedef const u8* (*DebugIterator)(void* internal, size_t el_size); typedef const u8* (*DebugIterator)(void* internal, size_t el_size);

View File

@ -254,7 +254,7 @@ static void importExtensionFunctions()
static void dump_gl_error(GLenum err) static void dump_gl_error(GLenum err)
{ {
debug_printf("GL error: "); debug_printf("OGL: ");
#define E(e) case e: debug_printf("%s\n", #e); break; #define E(e) case e: debug_printf("%s\n", #e); break;
switch (err) switch (err)
{ {

View File

@ -415,7 +415,7 @@ static void fn_store(HDATA* hd, const char* fn)
// fall back to heap alloc. // fall back to heap alloc.
if(!hd->fn) if(!hd->fn)
{ {
debug_printf("fn_store: very long filename (%d) %s\n", len, fn); debug_printf("H_MGR: very long filename (%d) %s\n", len, fn);
hd->fn = (const char*)malloc(len+1); hd->fn = (const char*)malloc(len+1);
// still failed - bail (avoid strcpy to 0) // still failed - bail (avoid strcpy to 0)
if(!hd->fn) if(!hd->fn)
@ -721,7 +721,7 @@ static int h_free_idx(i32 idx, HDATA* hd)
char buf[H_STRING_LEN]; char buf[H_STRING_LEN];
if(vtbl->to_string(hd->user, buf) < 0) if(vtbl->to_string(hd->user, buf) < 0)
strcpy(buf, "(error)"); // safe strcpy(buf, "(error)"); // safe
debug_printf("H_FREE %s %s accesses=%d %s\n", hd->type->name, fn, hd->num_derefs, buf); debug_printf("H_MGR: free %s %s accesses=%d %s\n", hd->type->name, fn, hd->num_derefs, buf);
fn_free(hd); fn_free(hd);
@ -919,6 +919,8 @@ int h_get_refcnt(Handle h)
void h_mgr_shutdown() void h_mgr_shutdown()
{ {
debug_printf("==h_mgr_shutdown== (all handle frees after this are leaks)\n");
// forcibly close all open handles // forcibly close all open handles
for(i32 i = 0; i <= last_in_use; i++) for(i32 i = 0; i <= last_in_use; i++)
{ {
@ -936,9 +938,6 @@ void h_mgr_shutdown()
if(!hd->tag) if(!hd->tag)
continue; continue;
if(hd->refs != 0)
debug_printf("leaked %s from %s\n", hd->type->name, hd->fn);
// disable caching; we need to release the resource now. // disable caching; we need to release the resource now.
hd->keep_open = 0; hd->keep_open = 0;
hd->refs = 0; hd->refs = 0;