1/*
2 * tracebuf.c
3 *
4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *  * Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  * Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *  * Neither the name Texas Instruments nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * Benchmark tracing utility
36 */
37
38#include "osApi.h"
39#include "tracebuf.h"
40#include "tracebuf_api.h"
41#include "report.h"
42
43typedef struct {
44      unsigned long loc;/* trace entry identification */
45      unsigned long ts;/* Timestamp */
46      unsigned long p1; /* Parameter 1 */
47      unsigned long p2; /* Parameter 2 */
48      char msg[MAX_TB_MSG];
49} tb_entry_t;
50
51typedef struct {
52      int pos;
53      int count;
54      int print_pos;
55      int nusers;
56      unsigned long self_delay;
57      unsigned long options;
58      tb_entry_t entry[1]; /* Array of entries */
59} tb_control_t;
60
61static tb_control_t *tb_control;
62
63static  int tb_control_size(void)
64{
65   return TI_FIELD_OFFSET(tb_control_t, entry) + sizeof(tb_entry_t)*TB_NUM_ENTRIES;
66}
67
68
69/* Initialization */
70int tb_init(unsigned long options)
71{
72   if (tb_control)
73   {
74      ++tb_control->nusers;
75      return 0;
76   }
77   tb_control = (tb_control_t *)TB_MALLOC(tb_control_size());
78   if (!tb_control)
79      return -1;
80   memset(tb_control, 0, tb_control_size());
81   tb_control->nusers = 1;
82
83   /* Measure self-delay */
84   tb_trace(0, 0, 0);
85   tb_trace(0, 0, 0);
86   tb_control->self_delay = tb_control->entry[1].ts - tb_control->entry[0].ts;
87   tb_control->pos = tb_control->count = 0;
88   tb_control->options = options;
89   return 0;
90}
91
92/* De-initialization */
93void tb_destroy(void)
94{
95   if (--tb_control->nusers)
96      return;
97   TB_FREE(tb_control );
98}
99
100static int tb_next(void)
101{
102    int pos;
103    if (!tb_control || tb_control->print_pos)
104       return -1;
105    pos = tb_control->pos;
106    tb_control->pos = (pos+1) % TB_NUM_ENTRIES;
107    ++tb_control->count;
108
109    tb_control->entry[tb_control->pos].ts =
110    tb_control->entry[tb_control->pos].loc=
111    tb_control->entry[tb_control->pos].p1 =
112    tb_control->entry[tb_control->pos].p2 = 0xffffffff;
113
114    return pos;
115}
116static void tb_autoprint(void)
117{
118    if ((tb_control->pos == 0) && (tb_control->count))
119    {
120        if (tb_control->options & TB_OPTION_PRINTONCE)
121        {
122            tb_printf();
123            tb_reset_option(TB_OPTION_PRINTONCE);
124        }
125        else if (tb_control->options & TB_OPTION_AUTOPRINT)
126        {
127            tb_printf();
128        }
129    }
130}
131
132/* Add trace entry. not safe, but will do */
133int tb_trace(int loc, unsigned long p1, unsigned long p2)
134{
135   int pos;
136
137   if ((tb_control->options & TB_OPTION_STOP) || ((pos = tb_next()) < 0))
138   {
139       return -1;
140   }
141   tb_control->entry[pos].ts = os_timeStampUs(NULL);
142   tb_control->entry[pos].loc= loc;
143   tb_control->entry[pos].p1 = p1;
144   tb_control->entry[pos].p2 = p2;
145
146   return pos;
147}
148void tb_dump(void)
149{
150	int j, pos;
151
152	WLAN_OS_REPORT(("Trace Dump:\n"));
153	WLAN_OS_REPORT(("===========\n\n"));
154    if (tb_control->count < TB_NUM_ENTRIES)
155    {
156        pos = 0;
157    }
158    else
159    {
160        pos = (tb_control->pos + 1) % TB_NUM_ENTRIES;
161    }
162	for (j=0; (unsigned int)j < tb_min((unsigned int)TB_NUM_ENTRIES,(unsigned int)tb_control->count); j++)
163	{
164		WLAN_OS_REPORT(("%4i %08x %08x %08x %08x\n", j,
165			(int)tb_control->entry[pos].ts,
166			(int)tb_control->entry[pos].loc,
167			(int)tb_control->entry[pos].p1,
168			(int)tb_control->entry[pos].p2));
169		pos = (pos+1) % TB_NUM_ENTRIES;
170	}
171
172}
173
174int tb_sprintf(const char *format ,...)
175{
176
177	va_list ap;
178    int pos;
179
180    if ((tb_control->options & TB_OPTION_STOP) || ((pos = tb_next()) < 0))
181    {
182        return -1;
183    }
184    tb_control->entry[pos].loc = TB_ID;
185	va_start(ap,format);
186	vsprintf(&tb_control->entry[pos].msg[0], format, ap);
187    tb_autoprint();
188    return pos;
189}
190
191void tb_printf(void)
192{
193	int j, pos;
194    unsigned long saved_options=tb_control->options;
195
196    tb_set_option(TB_OPTION_STOP);
197	WLAN_OS_REPORT(("Trace Dump:\n"));
198	WLAN_OS_REPORT(("===========\n\n"));
199    if (tb_control->count < TB_NUM_ENTRIES)
200    {
201        pos = 0;
202    }
203    else
204    {
205        pos = (tb_control->pos + 1) % TB_NUM_ENTRIES;
206    }
207	for (j=0; (unsigned int)j < tb_min((unsigned int)TB_NUM_ENTRIES,(unsigned int)tb_control->count); j++)
208	{
209		WLAN_OS_REPORT(("%4i id=0x%8x %s \n", j,
210tb_control->entry[pos].loc, tb_control->entry[pos].msg));
211		pos = (pos+1) % TB_NUM_ENTRIES;
212	}
213    tb_control->options = saved_options;
214}
215void tb_set_option(unsigned long option)
216{
217    tb_control->options |= option;
218}
219
220void tb_reset_option(unsigned long option)
221{
222    tb_control->options &= ~option;
223}
224
225void tb_scan(void)
226{
227
228  int j,k, Size, nAllocs=0, nFrees=0;
229  unsigned long address, Allocs=0, Frees=0;
230
231  for (j=0; j < TB_NUM_ENTRIES; j++)
232  {
233    Size = (int)tb_control->entry[j].p2;
234    if (Size > 0) /* Alloc */
235    {
236      nAllocs += 1;
237      Allocs  += Size;
238      address = tb_control->entry[j].p1;
239      for (k=j+1; k < TB_NUM_ENTRIES; k++)
240      {
241	if (address == tb_control->entry[k].p1)
242	{
243	  if (tb_control->entry[k].p2 != -Size)
244	  {
245	    TB_PRINTF("Bad free size at 0x%lx address = 0x%lx Size = %ld Allocated = %d\n",
246		   tb_control->entry[k].loc, tb_control->entry[k].p1, (long)tb_control->entry[k].p2, Size);
247	  }
248	  Frees  += tb_control->entry[k].p2;
249	  nFrees += 1;
250	  break;
251	}
252      }
253      if (k == TB_NUM_ENTRIES)
254      {
255	TB_PRINTF("Memory leak at 0x%lx address = 0x%lx Size = %d\n",
256	       tb_control->entry[j].loc, address, Size);
257      }
258    }
259  }
260  TB_PRINTF("tb_scan() Allocs = %ld nAllocs = %d Frees = %ld nFrees = %d\n", Allocs, nAllocs, Frees, nFrees);
261}
262
263