| /* |
| * tracebuf.c |
| * |
| * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name Texas Instruments nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * Benchmark tracing utility |
| */ |
| |
| #include "osApi.h" |
| #include "tracebuf.h" |
| #include "tracebuf_api.h" |
| #include "report.h" |
| |
| typedef struct { |
| unsigned long loc;/* trace entry identification */ |
| unsigned long ts;/* Timestamp */ |
| unsigned long p1; /* Parameter 1 */ |
| unsigned long p2; /* Parameter 2 */ |
| char msg[MAX_TB_MSG]; |
| } tb_entry_t; |
| |
| typedef struct { |
| int pos; |
| int count; |
| int print_pos; |
| int nusers; |
| unsigned long self_delay; |
| unsigned long options; |
| tb_entry_t entry[1]; /* Array of entries */ |
| } tb_control_t; |
| |
| static tb_control_t *tb_control; |
| |
| static int tb_control_size(void) |
| { |
| return TI_FIELD_OFFSET(tb_control_t, entry) + sizeof(tb_entry_t)*TB_NUM_ENTRIES; |
| } |
| |
| |
| /* Initialization */ |
| int tb_init(unsigned long options) |
| { |
| if (tb_control) |
| { |
| ++tb_control->nusers; |
| return 0; |
| } |
| tb_control = (tb_control_t *)TB_MALLOC(tb_control_size()); |
| if (!tb_control) |
| return -1; |
| memset(tb_control, 0, tb_control_size()); |
| tb_control->nusers = 1; |
| |
| /* Measure self-delay */ |
| tb_trace(0, 0, 0); |
| tb_trace(0, 0, 0); |
| tb_control->self_delay = tb_control->entry[1].ts - tb_control->entry[0].ts; |
| tb_control->pos = tb_control->count = 0; |
| tb_control->options = options; |
| return 0; |
| } |
| |
| /* De-initialization */ |
| void tb_destroy(void) |
| { |
| if (--tb_control->nusers) |
| return; |
| TB_FREE(tb_control ); |
| } |
| |
| static int tb_next(void) |
| { |
| int pos; |
| if (!tb_control || tb_control->print_pos) |
| return -1; |
| pos = tb_control->pos; |
| tb_control->pos = (pos+1) % TB_NUM_ENTRIES; |
| ++tb_control->count; |
| |
| tb_control->entry[tb_control->pos].ts = |
| tb_control->entry[tb_control->pos].loc= |
| tb_control->entry[tb_control->pos].p1 = |
| tb_control->entry[tb_control->pos].p2 = 0xffffffff; |
| |
| return pos; |
| } |
| static void tb_autoprint(void) |
| { |
| if ((tb_control->pos == 0) && (tb_control->count)) |
| { |
| if (tb_control->options & TB_OPTION_PRINTONCE) |
| { |
| tb_printf(); |
| tb_reset_option(TB_OPTION_PRINTONCE); |
| } |
| else if (tb_control->options & TB_OPTION_AUTOPRINT) |
| { |
| tb_printf(); |
| } |
| } |
| } |
| |
| /* Add trace entry. not safe, but will do */ |
| int tb_trace(int loc, unsigned long p1, unsigned long p2) |
| { |
| int pos; |
| |
| if ((tb_control->options & TB_OPTION_STOP) || ((pos = tb_next()) < 0)) |
| { |
| return -1; |
| } |
| tb_control->entry[pos].ts = os_timeStampUs(NULL); |
| tb_control->entry[pos].loc= loc; |
| tb_control->entry[pos].p1 = p1; |
| tb_control->entry[pos].p2 = p2; |
| |
| return pos; |
| } |
| void tb_dump(void) |
| { |
| int j, pos; |
| |
| WLAN_OS_REPORT(("Trace Dump:\n")); |
| WLAN_OS_REPORT(("===========\n\n")); |
| if (tb_control->count < TB_NUM_ENTRIES) |
| { |
| pos = 0; |
| } |
| else |
| { |
| pos = (tb_control->pos + 1) % TB_NUM_ENTRIES; |
| } |
| for (j=0; (unsigned int)j < tb_min((unsigned int)TB_NUM_ENTRIES,(unsigned int)tb_control->count); j++) |
| { |
| WLAN_OS_REPORT(("%4i %08x %08x %08x %08x\n", j, |
| (int)tb_control->entry[pos].ts, |
| (int)tb_control->entry[pos].loc, |
| (int)tb_control->entry[pos].p1, |
| (int)tb_control->entry[pos].p2)); |
| pos = (pos+1) % TB_NUM_ENTRIES; |
| } |
| |
| } |
| |
| int tb_sprintf(const char *format ,...) |
| { |
| |
| va_list ap; |
| int pos; |
| |
| if ((tb_control->options & TB_OPTION_STOP) || ((pos = tb_next()) < 0)) |
| { |
| return -1; |
| } |
| tb_control->entry[pos].loc = TB_ID; |
| va_start(ap,format); |
| vsprintf(&tb_control->entry[pos].msg[0], format, ap); |
| tb_autoprint(); |
| return pos; |
| } |
| |
| void tb_printf(void) |
| { |
| int j, pos; |
| unsigned long saved_options=tb_control->options; |
| |
| tb_set_option(TB_OPTION_STOP); |
| WLAN_OS_REPORT(("Trace Dump:\n")); |
| WLAN_OS_REPORT(("===========\n\n")); |
| if (tb_control->count < TB_NUM_ENTRIES) |
| { |
| pos = 0; |
| } |
| else |
| { |
| pos = (tb_control->pos + 1) % TB_NUM_ENTRIES; |
| } |
| for (j=0; (unsigned int)j < tb_min((unsigned int)TB_NUM_ENTRIES,(unsigned int)tb_control->count); j++) |
| { |
| WLAN_OS_REPORT(("%4i id=0x%8x %s \n", j, |
| tb_control->entry[pos].loc, tb_control->entry[pos].msg)); |
| pos = (pos+1) % TB_NUM_ENTRIES; |
| } |
| tb_control->options = saved_options; |
| } |
| void tb_set_option(unsigned long option) |
| { |
| tb_control->options |= option; |
| } |
| |
| void tb_reset_option(unsigned long option) |
| { |
| tb_control->options &= ~option; |
| } |
| |
| void tb_scan(void) |
| { |
| |
| int j,k, Size, nAllocs=0, nFrees=0; |
| unsigned long address, Allocs=0, Frees=0; |
| |
| for (j=0; j < TB_NUM_ENTRIES; j++) |
| { |
| Size = (int)tb_control->entry[j].p2; |
| if (Size > 0) /* Alloc */ |
| { |
| nAllocs += 1; |
| Allocs += Size; |
| address = tb_control->entry[j].p1; |
| for (k=j+1; k < TB_NUM_ENTRIES; k++) |
| { |
| if (address == tb_control->entry[k].p1) |
| { |
| if (tb_control->entry[k].p2 != -Size) |
| { |
| TB_PRINTF("Bad free size at 0x%lx address = 0x%lx Size = %ld Allocated = %d\n", |
| tb_control->entry[k].loc, tb_control->entry[k].p1, (long)tb_control->entry[k].p2, Size); |
| } |
| Frees += tb_control->entry[k].p2; |
| nFrees += 1; |
| break; |
| } |
| } |
| if (k == TB_NUM_ENTRIES) |
| { |
| TB_PRINTF("Memory leak at 0x%lx address = 0x%lx Size = %d\n", |
| tb_control->entry[j].loc, address, Size); |
| } |
| } |
| } |
| TB_PRINTF("tb_scan() Allocs = %ld nAllocs = %d Frees = %ld nFrees = %d\n", Allocs, nAllocs, Frees, nFrees); |
| } |
| |