/*
* 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);
}